Compare commits
45 Commits
tools/Rele
...
leilzh/dsc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f6a7e93d2 | ||
|
|
789ae9be8d | ||
|
|
0c2ca3edb3 | ||
|
|
4693131c0a | ||
|
|
7e9816a248 | ||
|
|
d109c1591b | ||
|
|
f3adef1a88 | ||
|
|
8629ec5ef2 | ||
|
|
af1c198d8a | ||
|
|
3e02d3029b | ||
|
|
0ff2c16c23 | ||
|
|
0177b0d38d | ||
|
|
b1dfd0d9fe | ||
|
|
f14d9684e2 | ||
|
|
f5f6f19bd5 | ||
|
|
1e4e88eca0 | ||
|
|
1870fbb6e4 | ||
|
|
ef2a88036a | ||
|
|
e17dd1a63f | ||
|
|
b221fda060 | ||
|
|
759c4dd3de | ||
|
|
477ddc55ff | ||
|
|
3c979da6df | ||
|
|
6aa1e325ce | ||
|
|
8a5c18528c | ||
|
|
7d046c073a | ||
|
|
db9071078a | ||
|
|
7580f890b3 | ||
|
|
86202df54b | ||
|
|
f345935258 | ||
|
|
7c78d04e45 | ||
|
|
d45870b1b3 | ||
|
|
005cca39d8 | ||
|
|
1972c13224 | ||
|
|
d119bc2b3d | ||
|
|
96b6c506b6 | ||
|
|
c46555b294 | ||
|
|
dd38c8ae9f | ||
|
|
ac75258adb | ||
|
|
f866223d31 | ||
|
|
7aa3490334 | ||
|
|
3bf8f414c8 | ||
|
|
fdd0ecc81d | ||
|
|
6415c1b4de | ||
|
|
336d40a3f9 |
1
.github/actions/spell-check/excludes.txt
vendored
@@ -131,4 +131,3 @@
|
||||
ignore$
|
||||
^src/modules/registrypreview/RegistryPreviewUILib/Controls/HexBox/.*$
|
||||
^src/common/CalculatorEngineCommon/exprtk\.hpp$
|
||||
src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage.cs
|
||||
|
||||
12
.github/actions/spell-check/expect.txt
vendored
@@ -27,7 +27,6 @@ admx
|
||||
advancedpaste
|
||||
advancedpasteui
|
||||
advancedpasteuishortcut
|
||||
advapi
|
||||
advfirewall
|
||||
AFeature
|
||||
affordances
|
||||
@@ -160,7 +159,6 @@ BUILDARCH
|
||||
BUILDNUMBER
|
||||
buildtransitive
|
||||
builttoroam
|
||||
BUNDLEINFO
|
||||
BVal
|
||||
BValue
|
||||
byapp
|
||||
@@ -394,7 +392,6 @@ DNLEN
|
||||
DONOTROUND
|
||||
DONTVALIDATEPATH
|
||||
dotnet
|
||||
downscale
|
||||
DPICHANGED
|
||||
DPIs
|
||||
DPSAPI
|
||||
@@ -484,7 +481,6 @@ examplehandler
|
||||
examplepowertoy
|
||||
EXAND
|
||||
EXCLUDEFROMCAPTURE
|
||||
EXECUTEDEFAULT
|
||||
executionpolicy
|
||||
exename
|
||||
exf
|
||||
@@ -864,7 +860,6 @@ LOCKTYPE
|
||||
LOGFONT
|
||||
LOGFONTW
|
||||
logon
|
||||
LOGMSG
|
||||
LOGPIXELSX
|
||||
LOGPIXELSY
|
||||
LOn
|
||||
@@ -922,7 +917,6 @@ LWA
|
||||
lwin
|
||||
LZero
|
||||
MAGTRANSFORM
|
||||
MAJORMINOR
|
||||
MAKEINTRESOURCE
|
||||
MAKEINTRESOURCEA
|
||||
MAKEINTRESOURCEW
|
||||
@@ -1001,9 +995,6 @@ mousepointercrosshairs
|
||||
mouseutils
|
||||
MOVESIZEEND
|
||||
MOVESIZESTART
|
||||
muxx
|
||||
muxxc
|
||||
muxxh
|
||||
MRM
|
||||
MRT
|
||||
mru
|
||||
@@ -1384,7 +1375,7 @@ QUNS
|
||||
RAII
|
||||
RAlt
|
||||
randi
|
||||
rasterization
|
||||
Rasterization
|
||||
Rasterize
|
||||
RAWINPUTDEVICE
|
||||
RAWINPUTHEADER
|
||||
@@ -1817,7 +1808,6 @@ ULONGLONG
|
||||
ums
|
||||
uncompilable
|
||||
UNCPRIORITY
|
||||
undefining
|
||||
UNDNAME
|
||||
UNICODETEXT
|
||||
unins
|
||||
|
||||
@@ -299,9 +299,6 @@
|
||||
"msvcp140_1_app.dll",
|
||||
"msvcp140_2_app.dll",
|
||||
"msvcp140_app.dll",
|
||||
"Namotion.Reflection.dll",
|
||||
"NJsonSchema.Annotations.dll",
|
||||
"NJsonSchema.dll",
|
||||
"vcamp140_app.dll",
|
||||
"vccorlib140_app.dll",
|
||||
"vcomp140_app.dll",
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# .pipelines/v2/nightly-prewarm.yml
|
||||
# Nightly pre-warm that reuses your existing ci.yml as-is
|
||||
|
||||
trigger: none
|
||||
pr: none
|
||||
|
||||
# (18:00 UTC) — adjust as you like
|
||||
schedules:
|
||||
- cron: "0 18 * * *" # UTC
|
||||
displayName: Nightly pre-warm (main)
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: true
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
|
||||
parameters:
|
||||
- name: buildPlatforms
|
||||
type: object
|
||||
default:
|
||||
- x64
|
||||
- arm64
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
displayName: "Enable MSBuild Caching"
|
||||
default: true
|
||||
- name: msBuildCacheIsReadOnly
|
||||
type: boolean
|
||||
displayName: "MSBuild Cache Read Only"
|
||||
default: false
|
||||
|
||||
extends:
|
||||
template: templates/pipeline-ci-build.yml
|
||||
parameters:
|
||||
buildPlatforms: ${{ parameters.buildPlatforms }}
|
||||
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
|
||||
msBuildCacheIsReadOnly: ${{ parameters.msBuildCacheIsReadOnly }}
|
||||
@@ -32,7 +32,7 @@ parameters:
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
displayName: "Enable MSBuild Caching"
|
||||
default: false
|
||||
default: true
|
||||
- name: runTests
|
||||
type: boolean
|
||||
displayName: "Run Tests"
|
||||
|
||||
@@ -43,6 +43,11 @@ parameters:
|
||||
displayName: "Build Using Visual Studio Preview"
|
||||
default: false
|
||||
|
||||
- name: enableAOT
|
||||
type: boolean
|
||||
displayName: "Enable AOT (Ahead-of-Time) Compilation for CmdPal"
|
||||
default: true
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
|
||||
variables:
|
||||
@@ -104,8 +109,8 @@ extends:
|
||||
useManagedIdentity: $(SigningUseManagedIdentity)
|
||||
clientId: $(SigningOriginalClientId)
|
||||
# Have msbuild use the release nuget config profile
|
||||
additionalBuildOptions: /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:EnableCmdPalAOT=${{ parameters.enableAOT }} /p:InstallerSuffix=${{ parameters.installerSuffix }}
|
||||
installerSuffix: ${{ parameters.installerSuffix }}
|
||||
additionalBuildOptions: /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:InstallerSuffix=${{ parameters.installerSuffix }} /p:EnableCmdPalAOT=true
|
||||
beforeBuildSteps:
|
||||
# Sets versions for all PowerToy created DLLs
|
||||
- pwsh: |-
|
||||
|
||||
@@ -50,9 +50,6 @@ parameters:
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
default: false
|
||||
- name: msBuildCacheIsReadOnly
|
||||
type: boolean
|
||||
default: true
|
||||
- name: runTests
|
||||
type: boolean
|
||||
default: true
|
||||
@@ -157,11 +154,6 @@ jobs:
|
||||
$MSBuildCacheParameters += " -reportfileaccesses"
|
||||
$MSBuildCacheParameters += " -p:MSBuildCacheEnabled=true"
|
||||
$MSBuildCacheParameters += " -p:MSBuildCacheLogDirectory=$(LogOutputDirectory)\MSBuildCacheLogs"
|
||||
# Cache read-only policy controlled by parameter
|
||||
$cacheIsReadOnly = "${{ parameters.msBuildCacheIsReadOnly }}"
|
||||
if ($cacheIsReadOnly -eq "True") {
|
||||
$MSBuildCacheParameters += " /p:MSBuildCacheRemoteCacheIsReadOnly=true"
|
||||
}
|
||||
Write-Host "MSBuildCacheParameters: $MSBuildCacheParameters"
|
||||
Write-Host "##vso[task.setvariable variable=MSBuildCacheParameters]$MSBuildCacheParameters"
|
||||
displayName: Prepare MSBuildCache variables
|
||||
|
||||
@@ -13,9 +13,6 @@ parameters:
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
default: false
|
||||
- name: msBuildCacheIsReadOnly
|
||||
type: boolean
|
||||
default: true
|
||||
- name: runTests
|
||||
type: boolean
|
||||
default: true
|
||||
@@ -55,7 +52,6 @@ stages:
|
||||
buildConfigurations: [Release]
|
||||
enablePackageCaching: true
|
||||
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
|
||||
msBuildCacheIsReadOnly: ${{ parameters.msBuildCacheIsReadOnly }}
|
||||
runTests: ${{ parameters.runTests }}
|
||||
useVSPreview: ${{ parameters.useVSPreview }}
|
||||
useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }}
|
||||
|
||||
@@ -132,39 +132,6 @@ steps:
|
||||
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
|
||||
|
||||
#### END MSI
|
||||
|
||||
#### BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
|
||||
- task: VSBuild@1
|
||||
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build SilentFilesInUseBAFunction
|
||||
inputs:
|
||||
solution: "**/installer/PowerToysSetup.sln"
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: >-
|
||||
/t:SilentFilesInUseBAFunction
|
||||
/p:RunBuildEvents=true;PerUser=${{parameters.buildUserInstaller}};RestorePackagesConfig=true;CIBuild=true
|
||||
/p:InstallerSuffix=${{ parameters.installerSuffix }}
|
||||
-restore -graph
|
||||
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-SilentFilesInUseBAFunction.binlog
|
||||
${{ parameters.additionalBuildOptions }}
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: false # don't undo our hard work above by deleting the msi
|
||||
msbuildArchitecture: x64
|
||||
maximumCpuCount: true
|
||||
|
||||
- ${{ if eq(parameters.codeSign, true) }}:
|
||||
- template: steps-esrp-signing.yml
|
||||
parameters:
|
||||
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign SilentFilesInUseBAFunction
|
||||
signingIdentity: ${{ parameters.signingIdentity }}
|
||||
inputs:
|
||||
FolderPath: 'installer/$(BuildPlatform)/$(BuildConfiguration)'
|
||||
signType: batchSigning
|
||||
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
|
||||
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
|
||||
|
||||
#### END BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
|
||||
|
||||
#### BOOTSTRAP BUILDING AND SIGNING
|
||||
- task: VSBuild@1
|
||||
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build VNext Bootstrapper
|
||||
@@ -181,7 +148,7 @@ steps:
|
||||
${{ parameters.additionalBuildOptions }}
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: false # don't undo our hard work above by deleting the MSI nor SilentFilesInUseBAFunction
|
||||
clean: false # don't undo our hard work above by deleting the MSI
|
||||
msbuildArchitecture: x64
|
||||
maximumCpuCount: true
|
||||
|
||||
|
||||
@@ -39,11 +39,6 @@ foreach ($csprojFile in $csprojFilesArray) {
|
||||
if ($csprojFile -like '*TemplateCmdPalExtension.csproj') {
|
||||
continue
|
||||
}
|
||||
|
||||
# The CmdPal.Core projects use a common shared props file, so skip them
|
||||
if ($csprojFile -like '*Microsoft.CmdPal.Core.*.csproj') {
|
||||
continue
|
||||
}
|
||||
|
||||
$importExists = Test-ImportSharedCsWinRTProps -filePath $csprojFile
|
||||
if (!$importExists) {
|
||||
|
||||
@@ -53,6 +53,10 @@ $nullVersionExceptions = @(
|
||||
"Microsoft.Windows.Widgets.dll",
|
||||
"AdaptiveCards.ObjectModel.WinUI3.dll",
|
||||
"AdaptiveCards.Rendering.WinUI3.dll") -join '|';
|
||||
$signatureExceptions = @(
|
||||
"Namotion.Reflection.dll",
|
||||
"NJsonSchema.Annotations.dll",
|
||||
"NJsonSchema.dll") -join '|';
|
||||
$totalFailure = 0;
|
||||
|
||||
Write-Host $DirPath;
|
||||
@@ -86,7 +90,7 @@ $items | ForEach-Object {
|
||||
}
|
||||
else {
|
||||
$auth = Get-AuthenticodeSignature $_.FullName
|
||||
if ($auth.SignerCertificate -eq $null) {
|
||||
if ($auth.SignerCertificate -eq $null -and $_.Name -notmatch $signatureExceptions) {
|
||||
Write-Host "Not Signed: " + $_.FullName
|
||||
$totalFailure++;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<_PropertySheetDisplayName>PowerToys.Root.Props</_PropertySheetDisplayName>
|
||||
<ForceImportBeforeCppProps>$(MsbuildThisFileDirectory)\Cpp.Build.props</ForceImportBeforeCppProps>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(MSBuildProjectExtension)' == '.csproj'">
|
||||
<PackageReference Include="StyleCop.Analyzers">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -3,9 +3,4 @@
|
||||
|
||||
<Import Project="$(MSBuildCachePackageRoot)\build\$(MSBuildCachePackageName).targets" Condition="'$(MSBuildCacheEnabled)' == 'true'" />
|
||||
<Import Project="$(MSBuildCacheSharedCompilationPackageRoot)\build\Microsoft.MSBuildCache.SharedCompilation.targets" Condition="'$(MSBuildCacheEnabled)' == 'true'" />
|
||||
|
||||
<!-- Override ManifestTool to the x64 host tool under WindowsSdkDir for all projects once the SDK path is known. -->
|
||||
<PropertyGroup Label="ManifestToolOverride">
|
||||
<ManifestTool Condition="Exists('$(WindowsSdkDir)bin\x64\mt.exe')">$(WindowsSdkDir)bin\x64\mt.exe</ManifestTool>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,7 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="AdaptiveCards.ObjectModel.WinUI3" Version="2.0.0-beta" />
|
||||
@@ -22,11 +21,11 @@
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Converters" Version="8.2.250402" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls.DataGrid" Version="7.1.2" />
|
||||
<PackageVersion Include="CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock" Version="0.1.250910-build.2249" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls.Markdown" Version="7.1.2" />
|
||||
<PackageVersion Include="CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock" Version="0.1.250703-build.2173" />
|
||||
<PackageVersion Include="ControlzEx" Version="6.0.0" />
|
||||
<PackageVersion Include="HelixToolkit" Version="2.24.0" />
|
||||
<PackageVersion Include="HelixToolkit.Core.Wpf" Version="2.24.0" />
|
||||
<PackageVersion Include="HtmlAgilityPack" Version="1.12.3" />
|
||||
<PackageVersion Include="hyjiacan.pinyin4net" Version="4.1.1" />
|
||||
<PackageVersion Include="Interop.Microsoft.Office.Interop.OneNote" Version="1.1.0.2" />
|
||||
<PackageVersion Include="LazyCache" Version="2.4.0" />
|
||||
@@ -38,7 +37,6 @@
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.8" />
|
||||
<!-- Including Microsoft.Bcl.AsyncInterfaces to force version, since it's used by Microsoft.SemanticKernel. -->
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Windows.CppWinRT" Version="2.0.240111.5" />
|
||||
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.16" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.8" />
|
||||
|
||||
@@ -1509,6 +1509,7 @@ SOFTWARE.
|
||||
- CommunityToolkit.WinUI.Converters
|
||||
- CommunityToolkit.WinUI.Extensions
|
||||
- CommunityToolkit.WinUI.UI.Controls.DataGrid
|
||||
- CommunityToolkit.WinUI.UI.Controls.Markdown
|
||||
- ControlzEx
|
||||
- HelixToolkit
|
||||
- HelixToolkit.Core.Wpf
|
||||
|
||||
@@ -638,7 +638,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.CommandPalette.Ex
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CommandPalette.Extensions.Toolkit", "src\modules\cmdpal\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj", "{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Core.Common", "src\modules\cmdpal\Core\Microsoft.CmdPal.Core.Common\Microsoft.CmdPal.Core.Common.csproj", "{14E62033-58D0-4A7D-8990-52F50A08BBBD}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Common", "src\modules\cmdpal\Microsoft.CmdPal.Common\Microsoft.CmdPal.Common.csproj", "{14E62033-58D0-4A7D-8990-52F50A08BBBD}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI", "src\modules\cmdpal\Microsoft.Terminal.UI\Microsoft.Terminal.UI.vcxproj", "{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}"
|
||||
EndProject
|
||||
@@ -728,7 +728,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerRename.UITests", "src\
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Core.ViewModels", "src\modules\cmdpal\Core\Microsoft.CmdPal.Core.ViewModels\Microsoft.CmdPal.Core.ViewModels.csproj", "{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Core.ViewModels", "src\modules\cmdpal\Microsoft.CmdPal.Core.ViewModels\Microsoft.CmdPal.Core.ViewModels.csproj", "{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0E556541-6A45-42CB-AE49-EE5A9BE05E7C}"
|
||||
EndProject
|
||||
@@ -3182,7 +3182,7 @@ Global
|
||||
{F3D09629-59A2-4924-A4B9-D6BFAA2C1B49} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{305DD37E-C85D-4B08-AAFE-7381FA890463} = {F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}
|
||||
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24} = {F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}
|
||||
{14E62033-58D0-4A7D-8990-52F50A08BBBD} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{14E62033-58D0-4A7D-8990-52F50A08BBBD} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
|
||||
{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
|
||||
{071E18A4-A530-46B8-AB7D-B862EE55E24E} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{C846F7A7-792A-47D9-B0CB-417C900EE03D} = {071E18A4-A530-46B8-AB7D-B862EE55E24E}
|
||||
|
||||
148
README.md
@@ -1,56 +1,38 @@
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: light)" srcset="./doc/images/readme/pt-hero.light.png" />
|
||||
<img src="./doc/images/readme/pt-hero.dark.png" />
|
||||
</picture>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
<span>Microsoft PowerToys</span>
|
||||
</h1>
|
||||
# Microsoft PowerToys
|
||||
|
||||
<h3 align="center">
|
||||
<a href="#-installation">Installation</a>
|
||||
<span> · </span>
|
||||
<a href="https://aka.ms/powertoys-docs">Documentation</a>
|
||||
<span> · </span>
|
||||
<a href="https://aka.ms/powertoys-releaseblog">Blog</a>
|
||||
<span> · </span>
|
||||
<a href="#-whats-new">Release notes</a>
|
||||
</h3>
|
||||
<br/><br/>
|
||||
Microsoft PowerToys is a collection of utilities that help you customize Windows and streamline everyday tasks.
|
||||
<br/><br/>
|
||||

|
||||
|
||||
| | | |
|
||||
|---|---|---|
|
||||
| [<img src="doc/images/icons/AdvancedPaste.png" alt="Advanced Paste icon" height="16"> Advanced Paste](https://aka.ms/PowerToysOverview_AdvancedPaste) | [<img src="doc/images/icons/Always%20On%20Top.png" alt="Always on Top icon" height="16"> Always on Top](https://aka.ms/PowerToysOverview_AoT) | [<img src="doc/images/icons/Awake.png" alt="Awake icon" height="16"> Awake](https://aka.ms/PowerToysOverview_Awake) |
|
||||
| [<img src="doc/images/icons/Color%20Picker.png" alt="Color Picker icon" height="16"> Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [<img src="doc/images/icons/Command%20Not%20Found.png" alt="Command Not Found icon" height="16"> Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | [<img src="doc/images/icons/Command Palette.png" alt="Command Palette icon" height="16"> Command Palette](https://aka.ms/PowerToysOverview_CmdPal) |
|
||||
| [<img src="doc/images/icons/Crop%20And%20Lock.png" alt="Crop and Lock icon" height="16"> Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [<img src="doc/images/icons/Environment%20Manager.png" alt="Environment Variables icon" height="16"> Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | [<img src="doc/images/icons/FancyZones.png" alt="FancyZones icon" height="16"> FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
|
||||
| [<img src="doc/images/icons/File%20Explorer%20Preview.png" alt="File Explorer Add-ons icon" height="16"> File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [<img src="doc/images/icons/File%20Locksmith.png" alt="File Locksmith icon" height="16"> File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [<img src="doc/images/icons/Host%20File%20Editor.png" alt="Hosts File Editor icon" height="16"> Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) |
|
||||
| [<img src="doc/images/icons/Image%20Resizer.png" alt="Image Resizer icon" height="16"> Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [<img src="doc/images/icons/Keyboard%20Manager.png" alt="Keyboard Manager icon" height="16"> Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [<img src="doc/images/icons/Find My Mouse.png" alt="Mouse Utilities icon" height="16"> Mouse Utilities](https://aka.ms/PowerToysOverview_MouseUtilities) |
|
||||
| [<img src="doc/images/icons/MouseWithoutBorders.png" alt="Mouse Without Borders icon" height="16"> Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [<img src="doc/images/icons/NewPlus.png" alt="New+ icon" height="16"> New+](https://aka.ms/PowerToysOverview_NewPlus) | [<img src="doc/images/icons/Peek.png" alt="Peek icon" height="16"> Peek](https://aka.ms/PowerToysOverview_Peek) |
|
||||
| [<img src="doc/images/icons/PowerRename.png" alt="PowerRename icon" height="16"> PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [<img src="doc/images/icons/PowerToys%20Run.png" alt="PowerToys Run icon" height="16"> PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [<img src="doc/images/icons/PowerAccent.png" alt="Quick Accent icon" height="16"> Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) |
|
||||
| [<img src="doc/images/icons/Registry%20Preview.png" alt="Registry Preview icon" height="16"> Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [<img src="doc/images/icons/MeasureTool.png" alt="Screen Ruler icon" height="16"> Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [<img src="doc/images/icons/Shortcut%20Guide.png" alt="Shortcut Guide icon" height="16"> Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
|
||||
| [<img src="doc/images/icons/PowerOCR.png" alt="Text Extractor icon" height="16"> Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [<img src="doc/images/icons/Workspaces.png" alt="Workspaces icon" height="16"> Workspaces](https://aka.ms/PowerToysOverview_Workspaces) | [<img src="doc/images/icons/ZoomIt.png" alt="ZoomIt icon" height="16"> ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) |
|
||||
[How to use PowerToys][usingPowerToys-docs-link] | [Downloads & Release notes][github-release-link] | [Contributing to PowerToys](#contributing) | [What's Happening](#whats-happening) | [Roadmap](#powertoys-roadmap)
|
||||
|
||||
## About
|
||||
|
||||
## 📋 Installation
|
||||
Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity. For more info on [PowerToys overviews and how to use the utilities][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://learn.microsoft.com/windows/dev-environment/overview), head over to [learn.microsoft.com][usingPowerToys-docs-link]!
|
||||
|
||||
For detailed installation instructions, visit the [installation docs](https://learn.microsoft.com/windows/powertoys/install).
|
||||
| | Current utilities: | |
|
||||
|--------------|--------------------|--------------|
|
||||
| [Advanced Paste](https://aka.ms/PowerToysOverview_AdvancedPaste) | [Always on Top](https://aka.ms/PowerToysOverview_AoT) | [PowerToys Awake](https://aka.ms/PowerToysOverview_Awake) |
|
||||
| [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | [Command Palette](https://aka.ms/PowerToysOverview_CmdPal) |
|
||||
| [Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
|
||||
| [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) |
|
||||
| [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [Mouse Utilities](https://aka.ms/PowerToysOverview_MouseUtilities) |
|
||||
| [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [New+](https://aka.ms/PowerToysOverview_NewPlus) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) |
|
||||
| [Peek](https://aka.ms/PowerToysOverview_Peek) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) |
|
||||
| [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) |
|
||||
| [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) |
|
||||
| [ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) |
|
||||
|
||||
Before you begin, make sure your device meets the system requirements:
|
||||
## Installing and running Microsoft PowerToys
|
||||
|
||||
> [!NOTE]
|
||||
> - Windows 11 or Windows 10 version 2004 (20H1 / build 19041) or newer
|
||||
> - 64-bit processor: x64 or ARM64
|
||||
> - Latest stable version of [Microsoft Edge WebView2 Runtime](https://go.microsoft.com/fwlink/p/?LinkId=2124703) is installed via the bootstrapper during setup
|
||||
### Requirements
|
||||
|
||||
Choose one of the installation methods below:
|
||||
- Windows 11 or Windows 10 version 2004 (code name 20H1 / build number 19041) or newer.
|
||||
- x64 or ARM64 processor
|
||||
- Our installer will install the following items:
|
||||
- [Microsoft Edge WebView2 Runtime](https://go.microsoft.com/fwlink/p/?LinkId=2124703) bootstrapper. This will install the latest version.
|
||||
|
||||
<details>
|
||||
<summary>Download .exe from GitHub</summary>
|
||||
### Via GitHub with EXE [Recommended]
|
||||
|
||||
Go to the [PowerToys GitHub releases][github-release-link], click Assets to reveal the downloads, and choose the installer that matches your architecture and install scope. For most devices, that's the x64 per-user installer.
|
||||
Go to the [Microsoft PowerToys GitHub releases page][github-release-link] and click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user.
|
||||
|
||||
<!-- items that need to be updated release to release -->
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.95%22
|
||||
@@ -67,49 +49,57 @@ Go to the [PowerToys GitHub releases][github-release-link], click Assets to reve
|
||||
| Machine wide - x64 | [PowerToysSetup-0.94.0-x64.exe][ptMachineX64] |
|
||||
| Machine wide - ARM64 | [PowerToysSetup-0.94.0-arm64.exe][ptMachineArm64] |
|
||||
|
||||
</details>
|
||||
This is our preferred method.
|
||||
|
||||
<details>
|
||||
<summary>Microsoft Store</summary>
|
||||
You can easily install PowerToys from the Microsoft Store:
|
||||
<p>
|
||||
<a style="text-decoration:none" href="https://aka.ms/getPowertoys">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: light)" srcset="doc/images/readme/StoreBadge-dark.png" width="148" />
|
||||
<img src="doc/images/readme/StoreBadge-light.png" width="148" />
|
||||
</picture></a>
|
||||
</p>
|
||||
</details>
|
||||
### Via Microsoft Store
|
||||
|
||||
Install from the [Microsoft Store's PowerToys page][microsoft-store-link]. You must be using the [new Microsoft Store](https://blogs.windows.com/windowsExperience/2021/06/24/building-a-new-open-microsoft-store-on-windows-11/), which is available for both Windows 11 and Windows 10.
|
||||
|
||||
<details>
|
||||
<summary>WinGet</summary>
|
||||
|
||||
### Via WinGet
|
||||
Download PowerToys from [WinGet][winget-link]. Updating PowerToys via winget will respect the current PowerToys installation scope. To install PowerToys, run the following command from the command line / PowerShell:
|
||||
|
||||
*User scope installer [default]*
|
||||
#### User scope installer [default]
|
||||
```powershell
|
||||
winget install Microsoft.PowerToys -s winget
|
||||
```
|
||||
|
||||
*Machine-wide scope installer*
|
||||
#### Machine-wide scope installer
|
||||
|
||||
```powershell
|
||||
winget install --scope machine Microsoft.PowerToys -s winget
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Other methods</summary>
|
||||
### Other install methods
|
||||
|
||||
There are [community driven install methods](./doc/unofficialInstallMethods.md) such as Chocolatey and Scoop. If these are your preferred install solutions, you can find the install instructions there.
|
||||
</details>
|
||||
|
||||
## ✨ What's new
|
||||
**Version 0.94 (September 2025)**
|
||||
## Third-Party Run Plugins
|
||||
|
||||
For an in-depth look at the latest changes, visit the [Windows Command Line blog](https://aka.ms/powertoys-releaseblog).
|
||||
There is a collection of [third-party plugins](./doc/thirdPartyRunPlugins.md) created by the community that aren't distributed with PowerToys.
|
||||
|
||||
**✨ Highlights**
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions of all types. Besides coding features / bug fixes, other ways to assist include spec writing, design, documentation, and finding bugs. We are excited to work with the power user community to build a set of tools for helping you get the most out of Windows.
|
||||
|
||||
We ask that **before you start work on a feature that you would like to contribute**, please read our [Contributor's Guide](CONTRIBUTING.md). We would be happy to work with you to figure out the best approach, provide guidance and mentorship throughout feature development, and help avoid any wasted or duplicate effort.
|
||||
|
||||
Most contributions require you to agree to a [Contributor License Agreement (CLA)][oss-CLA] declaring that you grant us the rights to use your contribution and that you have permission to do so.
|
||||
|
||||
For guidance on developing for PowerToys, please read the [developer docs](./doc/devdocs) for a detailed breakdown. This includes how to setup your computer to compile.
|
||||
|
||||
## What's Happening
|
||||
|
||||
### PowerToys Roadmap
|
||||
|
||||
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
|
||||
|
||||
### 0.94 - Sep 2025 Update
|
||||
|
||||
In this release, we focused on new features, stability, optimization improvements, and automation.
|
||||
|
||||
For an in-depth look at the latest changes, visit the [release blog](https://aka.ms/powertoys-releaseblog).
|
||||
|
||||
**✨Highlights**
|
||||
|
||||
- PowerToys Settings added a Settings search with fuzzy matching, suggestions, a results page, and UX polish to make finding options faster.
|
||||
- A comprehensive hotkey conflict detection system was introduced in Settings to surface and help resolve conflicting shortcuts. Note that the default hotkey settings (Win+Ctrl+Shift+T, Win+Ctrl+V, Win+Ctrl+T, Win+Shift+T) may overlap with existing Windows system shortcuts. This is expected. You can resolve the conflict by assigning different hotkeys.
|
||||
@@ -148,13 +138,13 @@ For an in-depth look at the latest changes, visit the [Windows Command Line blog
|
||||
- Allowed providers to override Dispose with a virtual method.
|
||||
- Fixed memory leaks by cleaning up removed or cancelled list items.
|
||||
- Sorted DateTime extension results by relevance for better usability.
|
||||
- Reduced search text "jiggling" by avoiding redundant change notifications.
|
||||
- Reduced search text “jiggling” by avoiding redundant change notifications.
|
||||
- Centralized automation notifications in a UIHelper for better accessibility. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- Preserved Adaptive Card action types during trimming via DynamicDependency.
|
||||
- Added an acrylic backdrop and refined styling to the context menu. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Prevented disposed pages and Settings windows from handling stale messages. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made the extension API easier to evolve without breaking clients.
|
||||
- Added "evil" sample pages to help reproduce tricky bugs.
|
||||
- Added “evil” sample pages to help reproduce tricky bugs.
|
||||
- Fixed WinGet trim-safety issues by replacing LINQ with manual iteration.
|
||||
- Cancelled stale list fetches to avoid older results overwriting newer ones in CmdPal.
|
||||
|
||||
@@ -230,10 +220,10 @@ For an in-depth look at the latest changes, visit the [Windows Command Line blog
|
||||
- Rewrote system command tests with a new test base and cleaner patterns.
|
||||
- Added unit tests for WebSearch and Shell extensions with mockable settings.
|
||||
- Added unit tests and abstractions for Apps and Bookmarks extensions.
|
||||
- Cleans up AI-generated tests; adds meaningful query tests across extensions.
|
||||
- Cleans up AI‑generated tests; adds meaningful query tests across extensions.
|
||||
- Removed the obsolete debug dialog from Settings for a smoother developer loop.
|
||||
|
||||
## 🛣️ Roadmap
|
||||
### What is being planned over the next few releases
|
||||
|
||||
For [v0.95][github-next-release-work], we'll work on the items below:
|
||||
|
||||
@@ -245,19 +235,9 @@ For [v0.95][github-next-release-work], we'll work on the items below:
|
||||
- New UI automation tests
|
||||
- Stability, bug fixes
|
||||
|
||||
## ❤️ PowerToys Community
|
||||
## PowerToys Community
|
||||
|
||||
The PowerToys team is extremely grateful to have the [support of an amazing active community][community-link]. The work you do is incredibly important. PowerToys wouldn't be nearly what it is today without your help filing bugs, updating documentation, guiding the design, or writing features. We want to say thank you and take time to recognize your work. Your contributions and feedback improve PowerToys month after month!
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions of all types. Besides coding features / bug fixes, other ways to assist include spec writing, design, documentation, and finding bugs. We are excited to work with the power user community to build a set of tools for helping you get the most out of Windows.
|
||||
|
||||
We ask that **before you start work on a feature that you would like to contribute**, please read our [Contributor's Guide](CONTRIBUTING.md). We would be happy to work with you to figure out the best approach, provide guidance and mentorship throughout feature development, and help avoid any wasted or duplicate effort.
|
||||
|
||||
Most contributions require you to agree to a [Contributor License Agreement (CLA)][oss-CLA] declaring that you grant us the rights to use your contribution and that you have permission to do so.
|
||||
|
||||
For guidance on developing for PowerToys, please read the [developer docs](./doc/devdocs) for a detailed breakdown. This includes how to setup your computer to compile.
|
||||
The PowerToys team is extremely grateful to have the [support of an amazing active community][community-link]. The work you do is incredibly important. PowerToys wouldn’t be nearly what it is today without your help filing bugs, updating documentation, guiding the design, or writing features. We want to say thank you and take time to recognize your work. Month by month, you directly help make PowerToys a better piece of software.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 13 KiB |
BIN
doc/images/overview/PT_hero_image.png
Normal file
|
After Width: | Height: | Size: 394 KiB |
BIN
doc/images/overview/PT_large.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
doc/images/overview/PT_small.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 464 KiB |
|
Before Width: | Height: | Size: 502 KiB |
@@ -26,7 +26,6 @@
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<TargetName>SilentFilesInUseBAFunction</TargetName>
|
||||
<ProjectName>PowerToysSetupCustomActionsVNext</ProjectName>
|
||||
<ProjectModuleDefinitionFile>bafunctions.def</ProjectModuleDefinitionFile>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
@@ -92,31 +91,5 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- C++ source compile-specific things for Debug/Release configurations -->
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
@@ -19,9 +19,7 @@ namespace ManagedCommon
|
||||
private static readonly string Error = "Error";
|
||||
private static readonly string Warning = "Warning";
|
||||
private static readonly string Info = "Info";
|
||||
#if DEBUG
|
||||
private static readonly string Debug = "Debug";
|
||||
#endif
|
||||
private static readonly string TraceFlag = "Trace";
|
||||
|
||||
private static readonly string Version = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? "Unknown";
|
||||
@@ -153,9 +151,7 @@ namespace ManagedCommon
|
||||
|
||||
public static void LogDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
#if DEBUG
|
||||
Log(message, Debug, memberName, sourceFilePath, sourceLineNumber);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void LogTrace([System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<PackageReference Include="Appium.WebDriver" />
|
||||
<PackageReference Include="MSTest" />
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
<PackageReference Include="System.Net.Http" />
|
||||
<PackageReference Include="System.Private.Uri" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" />
|
||||
<PackageReference Include="CoenM.ImageSharp.ImageHash" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -12,6 +12,156 @@
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<!-- Other app resources here -->
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Style x:Key="SubtleButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
|
||||
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
|
||||
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="FocusVisualMargin" Value="-3" />
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AnimatedIcon.State="Normal"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Foreground="{TemplateBinding Foreground}">
|
||||
<ContentPresenter.BackgroundTransition>
|
||||
<BrushTransition Duration="0:0:0.083" />
|
||||
</ContentPresenter.BackgroundTransition>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</ContentPresenter>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -21,6 +21,157 @@
|
||||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.SettingsControls/SettingsExpander/SettingsExpander.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Style x:Key="SubtleButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
|
||||
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
|
||||
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="FocusVisualMargin" Value="-3" />
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AnimatedIcon.State="Normal"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Foreground="{TemplateBinding Foreground}">
|
||||
<ContentPresenter.BackgroundTransition>
|
||||
<BrushTransition Duration="0:0:0.083" />
|
||||
</ContentPresenter.BackgroundTransition>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</ContentPresenter>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<x:Double x:Key="SecondaryTextFontSize">12</x:Double>
|
||||
<Style x:Key="SecondaryTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="{StaticResource SecondaryTextFontSize}" />
|
||||
|
||||
@@ -9,6 +9,157 @@
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Style x:Key="SubtleButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
|
||||
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
|
||||
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="FocusVisualMargin" Value="-3" />
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AnimatedIcon.State="Normal"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Foreground="{TemplateBinding Foreground}">
|
||||
<ContentPresenter.BackgroundTransition>
|
||||
<BrushTransition Duration="0:0:0.083" />
|
||||
</ContentPresenter.BackgroundTransition>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</ContentPresenter>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -27,6 +27,160 @@
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
|
||||
|
||||
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
|
||||
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Style x:Key="SubtleButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
|
||||
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
|
||||
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="FocusVisualMargin" Value="-3" />
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AnimatedIcon.State="Normal"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Foreground="{TemplateBinding Foreground}">
|
||||
<ContentPresenter.BackgroundTransition>
|
||||
<BrushTransition Duration="0:0:0.083" />
|
||||
</ContentPresenter.BackgroundTransition>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
|
||||
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</ContentPresenter>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
<tkconverters:StringVisibilityConverter
|
||||
x:Key="StringVisibilityConverter"
|
||||
EmptyValue="Collapsed"
|
||||
|
||||
@@ -8,28 +8,21 @@
|
||||
#include "common/utils/process_path.h"
|
||||
#include "common/utils/excluded_apps.h"
|
||||
#include "common/utils/MsWindowsSettings.h"
|
||||
#include <winrt/Windows.Graphics.h>
|
||||
|
||||
#include <winrt/Microsoft.UI.Composition.Interop.h>
|
||||
#include <winrt/Microsoft.UI.Dispatching.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Media.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Hosting.h>
|
||||
#include <winrt/Microsoft.UI.Interop.h>
|
||||
#include <winrt/Microsoft.UI.Content.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef COMPOSITION
|
||||
namespace winrt
|
||||
{
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Composition;
|
||||
}
|
||||
|
||||
namespace muxc = winrt::Microsoft::UI::Composition;
|
||||
namespace muxx = winrt::Microsoft::UI::Xaml;
|
||||
namespace muxxc = winrt::Microsoft::UI::Xaml::Controls;
|
||||
namespace muxxh = winrt::Microsoft::UI::Xaml::Hosting;
|
||||
namespace ABI
|
||||
{
|
||||
using namespace ABI::Windows::System;
|
||||
using namespace ABI::Windows::UI::Composition::Desktop;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma region Super_Sonar_Base_Code
|
||||
|
||||
@@ -77,11 +70,11 @@ protected:
|
||||
int m_sonarRadius = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS;
|
||||
int m_sonarZoomFactor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM;
|
||||
DWORD m_fadeDuration = FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS;
|
||||
int m_finalAlphaNumerator = 100; // legacy (root now always animates to 1.0; kept for GDI fallback compatibility)
|
||||
int m_finalAlphaNumerator = FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY;
|
||||
std::vector<std::wstring> m_excludedApps;
|
||||
int m_shakeMinimumDistance = FIND_MY_MOUSE_DEFAULT_SHAKE_MINIMUM_DISTANCE;
|
||||
static constexpr int FinalAlphaDenominator = 100;
|
||||
winrt::Microsoft::UI::Dispatching::DispatcherQueueController m_dispatcherQueueController{ nullptr };
|
||||
winrt::DispatcherQueueController m_dispatcherQueueController{ nullptr };
|
||||
|
||||
// Don't consider movements started past these milliseconds to detect shaking.
|
||||
int m_shakeIntervalMs = FIND_MY_MOUSE_DEFAULT_SHAKE_INTERVAL_MS;
|
||||
@@ -89,6 +82,7 @@ protected:
|
||||
int m_shakeFactor = FIND_MY_MOUSE_DEFAULT_SHAKE_FACTOR;
|
||||
|
||||
private:
|
||||
|
||||
// Save the mouse movement that occurred in any direction.
|
||||
struct PointerRecentMovement
|
||||
{
|
||||
@@ -165,6 +159,7 @@ bool SuperSonar<D>::Initialize(HINSTANCE hinst)
|
||||
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
|
||||
WNDCLASS wc{};
|
||||
|
||||
if (!GetClassInfoW(hinst, className, &wc))
|
||||
{
|
||||
wc.lpfnWndProc = s_WndProc;
|
||||
@@ -176,28 +171,14 @@ bool SuperSonar<D>::Initialize(HINSTANCE hinst)
|
||||
|
||||
if (!RegisterClassW(&wc))
|
||||
{
|
||||
Logger::error("RegisterClassW failed. GetLastError={}", GetLastError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// else: class already registered
|
||||
|
||||
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinst, nullptr);
|
||||
if (!m_hwndOwner)
|
||||
{
|
||||
Logger::error("Failed to create owner window. GetLastError={}", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD exStyle = WS_EX_TOOLWINDOW | Shim()->GetExtendedStyle();
|
||||
HWND created = CreateWindowExW(exStyle, className, windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hinst, this);
|
||||
if (!created)
|
||||
{
|
||||
Logger::error("CreateWindowExW failed. GetLastError={}", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW | Shim()->GetExtendedStyle();
|
||||
return CreateWindowExW(exStyle, className, windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hinst, this) != nullptr;
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
@@ -245,8 +226,7 @@ LRESULT SuperSonar<D>::BaseWndProc(UINT message, WPARAM wParam, LPARAM lParam) n
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
if (!OnSonarCreate())
|
||||
return -1;
|
||||
if(!OnSonarCreate()) return -1;
|
||||
UpdateMouseSnooping();
|
||||
return 0;
|
||||
|
||||
@@ -334,7 +314,8 @@ void SuperSonar<D>::OnSonarKeyboardInput(RAWINPUT const& input)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_activationMethod != FindMyMouseActivationMethod::DoubleRightControlKey && m_activationMethod != FindMyMouseActivationMethod::DoubleLeftControlKey) || input.data.keyboard.VKey != VK_CONTROL)
|
||||
if ((m_activationMethod != FindMyMouseActivationMethod::DoubleRightControlKey && m_activationMethod != FindMyMouseActivationMethod::DoubleLeftControlKey)
|
||||
|| input.data.keyboard.VKey != VK_CONTROL)
|
||||
{
|
||||
StopSonar();
|
||||
return;
|
||||
@@ -345,7 +326,8 @@ void SuperSonar<D>::OnSonarKeyboardInput(RAWINPUT const& input)
|
||||
bool leftCtrlPressed = (input.data.keyboard.Flags & RI_KEY_E0) == 0;
|
||||
bool rightCtrlPressed = (input.data.keyboard.Flags & RI_KEY_E0) != 0;
|
||||
|
||||
if ((m_activationMethod == FindMyMouseActivationMethod::DoubleRightControlKey && !rightCtrlPressed) || (m_activationMethod == FindMyMouseActivationMethod::DoubleLeftControlKey && !leftCtrlPressed))
|
||||
if ((m_activationMethod == FindMyMouseActivationMethod::DoubleRightControlKey && !rightCtrlPressed)
|
||||
|| (m_activationMethod == FindMyMouseActivationMethod::DoubleLeftControlKey && !leftCtrlPressed))
|
||||
{
|
||||
StopSonar();
|
||||
return;
|
||||
@@ -394,6 +376,7 @@ void SuperSonar<D>::OnSonarKeyboardInput(RAWINPUT const& input)
|
||||
GetCursorPos(&m_lastKeyPos);
|
||||
UpdateMouseSnooping();
|
||||
}
|
||||
Logger::info("Detecting double left control click with {} ms interval.", doubleClickInterval);
|
||||
m_lastKeyTime = now;
|
||||
m_lastKeyPos = ptCursor;
|
||||
}
|
||||
@@ -419,13 +402,14 @@ template<typename D>
|
||||
void SuperSonar<D>::DetectShake()
|
||||
{
|
||||
ULONGLONG shakeStartTick = GetTickCount64() - m_shakeIntervalMs;
|
||||
|
||||
|
||||
// Prune the story of movements for those movements that started too long ago.
|
||||
std::erase_if(m_movementHistory, [shakeStartTick](const PointerRecentMovement& movement) { return movement.tick < shakeStartTick; });
|
||||
|
||||
|
||||
|
||||
double distanceTravelled = 0;
|
||||
LONGLONG currentX = 0, minX = 0, maxX = 0;
|
||||
LONGLONG currentY = 0, minY = 0, maxY = 0;
|
||||
LONGLONG currentX=0, minX=0, maxX=0;
|
||||
LONGLONG currentY=0, minY=0, maxY=0;
|
||||
|
||||
for (const PointerRecentMovement& movement : m_movementHistory)
|
||||
{
|
||||
@@ -437,22 +421,23 @@ void SuperSonar<D>::DetectShake()
|
||||
minY = min(currentY, minY);
|
||||
maxY = max(currentY, maxY);
|
||||
}
|
||||
|
||||
|
||||
if (distanceTravelled < m_shakeMinimumDistance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Size of the rectangle that the pointer moved in.
|
||||
double rectangleWidth = static_cast<double>(maxX) - minX;
|
||||
double rectangleHeight = static_cast<double>(maxY) - minY;
|
||||
double rectangleWidth = static_cast<double>(maxX) - minX;
|
||||
double rectangleHeight = static_cast<double>(maxY) - minY;
|
||||
|
||||
double diagonal = sqrt(rectangleWidth * rectangleWidth + rectangleHeight * rectangleHeight);
|
||||
if (diagonal > 0 && distanceTravelled / diagonal > (m_shakeFactor / 100.f))
|
||||
if (diagonal > 0 && distanceTravelled / diagonal > (m_shakeFactor/100.f))
|
||||
{
|
||||
m_movementHistory.clear();
|
||||
StartSonar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
@@ -468,7 +453,7 @@ void SuperSonar<D>::OnSonarMouseInput(RAWINPUT const& input)
|
||||
{
|
||||
LONG relativeX = 0;
|
||||
LONG relativeY = 0;
|
||||
if ((input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) == MOUSE_MOVE_ABSOLUTE && (input.data.mouse.lLastX != 0 || input.data.mouse.lLastY != 0))
|
||||
if ((input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) == MOUSE_MOVE_ABSOLUTE && (input.data.mouse.lLastX!=0 || input.data.mouse.lLastY!=0))
|
||||
{
|
||||
// Getting absolute mouse coordinates. Likely inside a VM / RDP session.
|
||||
if (m_seenAnAbsoluteMousePosition)
|
||||
@@ -497,7 +482,7 @@ void SuperSonar<D>::OnSonarMouseInput(RAWINPUT const& input)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_movementHistory.push_back({ .diff = { .x = relativeX, .y = relativeY }, .tick = GetTickCount64() });
|
||||
m_movementHistory.push_back({ .diff = { .x=relativeX, .y=relativeY }, .tick = GetTickCount64() });
|
||||
// Mouse movement changed directions. Take the opportunity do detect shake.
|
||||
DetectShake();
|
||||
}
|
||||
@@ -506,6 +491,7 @@ void SuperSonar<D>::OnSonarMouseInput(RAWINPUT const& input)
|
||||
{
|
||||
m_movementHistory.push_back({ .diff = { .x = relativeX, .y = relativeY }, .tick = GetTickCount64() });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (input.data.mouse.usButtonFlags)
|
||||
@@ -532,6 +518,7 @@ void SuperSonar<D>::StartSonar()
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::info("Focusing the sonar on the mouse cursor.");
|
||||
Trace::MousePointerFocused();
|
||||
// Cover the entire virtual screen.
|
||||
// HACK: Draw with 1 pixel off. Otherwise, Windows glitches the task bar transparency when a transparent window fill the whole screen.
|
||||
@@ -646,26 +633,12 @@ struct CompositionSpotlight : SuperSonar<CompositionSpotlight>
|
||||
|
||||
DWORD GetExtendedStyle()
|
||||
{
|
||||
// Remove WS_EX_NOREDIRECTIONBITMAP for Composition/XAML to allow DWM redirection.
|
||||
return 0;
|
||||
return WS_EX_NOREDIRECTIONBITMAP;
|
||||
}
|
||||
|
||||
void AfterMoveSonar()
|
||||
{
|
||||
const float scale = static_cast<float>(m_surface.XamlRoot().RasterizationScale());
|
||||
// Move gradient center
|
||||
if (m_spotlightMaskGradient)
|
||||
{
|
||||
m_spotlightMaskGradient.EllipseCenter({ static_cast<float>(m_sonarPos.x) / scale,
|
||||
static_cast<float>(m_sonarPos.y) / scale });
|
||||
}
|
||||
// Move spotlight visual (color fill) below masked backdrop
|
||||
if (m_spotlight)
|
||||
{
|
||||
m_spotlight.Offset({ static_cast<float>(m_sonarPos.x) / scale,
|
||||
static_cast<float>(m_sonarPos.y) / scale,
|
||||
0.0f });
|
||||
}
|
||||
m_spotlight.Offset({ static_cast<float>(m_sonarPos.x), static_cast<float>(m_sonarPos.y), 0.0f });
|
||||
}
|
||||
|
||||
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
@@ -673,29 +646,24 @@ struct CompositionSpotlight : SuperSonar<CompositionSpotlight>
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
if (!OnCompositionCreate())
|
||||
return -1;
|
||||
return BaseWndProc(message, wParam, lParam);
|
||||
return OnCompositionCreate() && BaseWndProc(message, wParam, lParam);
|
||||
|
||||
case WM_OPACITY_ANIMATION_COMPLETED:
|
||||
OnOpacityAnimationCompleted();
|
||||
break;
|
||||
case WM_SIZE:
|
||||
UpdateIslandSize();
|
||||
break;
|
||||
}
|
||||
return BaseWndProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
void SetSonarVisibility(bool visible)
|
||||
{
|
||||
m_batch = m_compositor.GetCommitBatch(muxc::CompositionBatchTypes::Animation);
|
||||
m_batch = m_compositor.GetCommitBatch(winrt::CompositionBatchTypes::Animation);
|
||||
BOOL isEnabledAnimations = GetAnimationsEnabled();
|
||||
m_animation.Duration(std::chrono::milliseconds{ isEnabledAnimations ? m_fadeDuration : 1 });
|
||||
m_batch.Completed([hwnd = m_hwnd](auto&&, auto&&) {
|
||||
PostMessage(hwnd, WM_OPACITY_ANIMATION_COMPLETED, 0, 0);
|
||||
});
|
||||
m_root.Opacity(visible ? 1.0f : 0.0f);
|
||||
m_root.Opacity(visible ? static_cast<float>(m_finalAlphaNumerator) / FinalAlphaDenominator : 0.0f);
|
||||
if (visible)
|
||||
{
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
@@ -711,138 +679,54 @@ private:
|
||||
bool OnCompositionCreate()
|
||||
try
|
||||
{
|
||||
// Creating composition resources
|
||||
// Ensure a DispatcherQueue bound to this thread (required by WinAppSDK composition/XAML)
|
||||
if (!m_dispatcherQueueController)
|
||||
{
|
||||
// Ensure COM is initialized
|
||||
try
|
||||
{
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
// COM STA initialized
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error("Failed to initialize COM apartment: {}", winrt::to_string(e.message()));
|
||||
return false;
|
||||
}
|
||||
// We need a dispatcher queue.
|
||||
DispatcherQueueOptions options = {
|
||||
sizeof(options),
|
||||
DQTYPE_THREAD_CURRENT,
|
||||
DQTAT_COM_ASTA,
|
||||
};
|
||||
ABI::IDispatcherQueueController* controller;
|
||||
winrt::check_hresult(CreateDispatcherQueueController(options, &controller));
|
||||
*winrt::put_abi(m_dispatcherQueueController) = controller;
|
||||
|
||||
try
|
||||
{
|
||||
m_dispatcherQueueController =
|
||||
winrt::Microsoft::UI::Dispatching::DispatcherQueueController::CreateOnCurrentThread();
|
||||
// DispatcherQueueController created
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error("Failed to create DispatcherQueueController: {}", winrt::to_string(e.message()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Create the compositor for our window.
|
||||
m_compositor = winrt::Compositor();
|
||||
ABI::IDesktopWindowTarget* target;
|
||||
winrt::check_hresult(m_compositor.as<ABI::ICompositorDesktopInterop>()->CreateDesktopWindowTarget(m_hwnd, false, &target));
|
||||
*winrt::put_abi(m_target) = target;
|
||||
|
||||
// 1) Create a XAML island and attach it to this HWND
|
||||
try
|
||||
{
|
||||
m_island = winrt::Microsoft::UI::Xaml::Hosting::DesktopWindowXamlSource{};
|
||||
auto windowId = winrt::Microsoft::UI::GetWindowIdFromWindow(m_hwnd);
|
||||
m_island.Initialize(windowId);
|
||||
// Xaml source initialized
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error("Failed to create XAML island: {}", winrt::to_string(e.message()));
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateIslandSize();
|
||||
// Island size set
|
||||
|
||||
// 2) Create a XAML container to host the Composition child visual
|
||||
m_surface = winrt::Microsoft::UI::Xaml::Controls::Grid{};
|
||||
|
||||
// A transparent background keeps hit-testing consistent vs. null brush
|
||||
m_surface.Background(winrt::Microsoft::UI::Xaml::Media::SolidColorBrush{
|
||||
winrt::Microsoft::UI::Colors::Transparent() });
|
||||
m_surface.HorizontalAlignment(muxx::HorizontalAlignment::Stretch);
|
||||
m_surface.VerticalAlignment(muxx::VerticalAlignment::Stretch);
|
||||
|
||||
m_island.Content(m_surface);
|
||||
|
||||
// 3) Get the compositor from the XAML visual tree (pure MUXC path)
|
||||
try
|
||||
{
|
||||
auto elementVisual =
|
||||
winrt::Microsoft::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(m_surface);
|
||||
m_compositor = elementVisual.Compositor();
|
||||
// Compositor acquired
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
{
|
||||
Logger::error("Failed to get compositor: {}", winrt::to_string(e.message()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4) Build the composition tree
|
||||
// Our composition tree:
|
||||
//
|
||||
// [root] ContainerVisual (fills host)
|
||||
// \ LayerVisual
|
||||
// \ [backdrop dim * radial gradient mask (hole)]
|
||||
// [root] ContainerVisual
|
||||
// \ LayerVisual
|
||||
// \[gray backdrop]
|
||||
// [spotlight]
|
||||
m_root = m_compositor.CreateContainerVisual();
|
||||
m_root.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_root.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_root.Opacity(0.0f);
|
||||
|
||||
// Insert our root as a hand-in Visual under the XAML element
|
||||
winrt::Microsoft::UI::Xaml::Hosting::ElementCompositionPreview::SetElementChildVisual(m_surface, m_root);
|
||||
m_target.Root(m_root);
|
||||
|
||||
auto layer = m_compositor.CreateLayerVisual();
|
||||
layer.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
layer.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_root.Children().InsertAtTop(layer);
|
||||
|
||||
const float scale = static_cast<float>(m_surface.XamlRoot().RasterizationScale());
|
||||
const float rDip = m_sonarRadiusFloat / scale;
|
||||
const float zoom = static_cast<float>(m_sonarZoomFactor);
|
||||
|
||||
// Spotlight shape (below backdrop, visible through hole)
|
||||
m_circleGeometry = m_compositor.CreateEllipseGeometry();
|
||||
m_circleShape = m_compositor.CreateSpriteShape(m_circleGeometry);
|
||||
m_circleShape.FillBrush(m_compositor.CreateColorBrush(m_spotlightColor));
|
||||
m_circleShape.Offset({ rDip * zoom, rDip * zoom });
|
||||
m_spotlight = m_compositor.CreateShapeVisual();
|
||||
m_spotlight.Size({ rDip * 2 * zoom, rDip * 2 * zoom });
|
||||
m_spotlight.AnchorPoint({ 0.5f, 0.5f });
|
||||
m_spotlight.Shapes().Append(m_circleShape);
|
||||
layer.Children().InsertAtTop(m_spotlight);
|
||||
|
||||
// Dim color (source)
|
||||
m_dimColorBrush = m_compositor.CreateColorBrush(m_backgroundColor);
|
||||
// Radial gradient mask (center transparent, outer opaque)
|
||||
m_spotlightMaskGradient = m_compositor.CreateRadialGradientBrush();
|
||||
m_spotlightMaskGradient.MappingMode(muxc::CompositionMappingMode::Absolute);
|
||||
m_maskStopCenter = m_compositor.CreateColorGradientStop();
|
||||
m_maskStopCenter.Offset(0.0f);
|
||||
m_maskStopCenter.Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
|
||||
m_maskStopInner = m_compositor.CreateColorGradientStop();
|
||||
m_maskStopInner.Offset(0.995f);
|
||||
m_maskStopInner.Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
|
||||
m_maskStopOuter = m_compositor.CreateColorGradientStop();
|
||||
m_maskStopOuter.Offset(1.0f);
|
||||
m_maskStopOuter.Color(winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 255, 255));
|
||||
m_spotlightMaskGradient.ColorStops().Append(m_maskStopCenter);
|
||||
m_spotlightMaskGradient.ColorStops().Append(m_maskStopInner);
|
||||
m_spotlightMaskGradient.ColorStops().Append(m_maskStopOuter);
|
||||
m_spotlightMaskGradient.EllipseCenter({ rDip * zoom, rDip * zoom });
|
||||
m_spotlightMaskGradient.EllipseRadius({ rDip * zoom, rDip * zoom });
|
||||
|
||||
m_maskBrush = m_compositor.CreateMaskBrush();
|
||||
m_maskBrush.Source(m_dimColorBrush);
|
||||
m_maskBrush.Mask(m_spotlightMaskGradient);
|
||||
|
||||
m_backdrop = m_compositor.CreateSpriteVisual();
|
||||
m_backdrop.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_backdrop.Brush(m_maskBrush);
|
||||
m_backdrop.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_backdrop.Brush(m_compositor.CreateColorBrush(m_backgroundColor));
|
||||
layer.Children().InsertAtTop(m_backdrop);
|
||||
|
||||
// 5) Implicit opacity animation on the root
|
||||
m_circleGeometry = m_compositor.CreateEllipseGeometry(); // radius set via expression animation
|
||||
m_circleShape = m_compositor.CreateSpriteShape(m_circleGeometry);
|
||||
m_circleShape.FillBrush(m_compositor.CreateColorBrush(m_spotlightColor));
|
||||
m_circleShape.Offset({ m_sonarRadiusFloat * m_sonarZoomFactor, m_sonarRadiusFloat * m_sonarZoomFactor });
|
||||
m_spotlight = m_compositor.CreateShapeVisual();
|
||||
m_spotlight.Size({ m_sonarRadiusFloat * 2 * m_sonarZoomFactor, m_sonarRadiusFloat * 2 * m_sonarZoomFactor });
|
||||
m_spotlight.AnchorPoint({ 0.5f, 0.5f });
|
||||
m_spotlight.Shapes().Append(m_circleShape);
|
||||
|
||||
layer.Children().InsertAtTop(m_spotlight);
|
||||
|
||||
// Implicitly animate the alpha.
|
||||
m_animation = m_compositor.CreateScalarKeyFrameAnimation();
|
||||
m_animation.Target(L"Opacity");
|
||||
m_animation.InsertExpressionKeyFrame(1.0f, L"this.FinalValue");
|
||||
@@ -851,31 +735,20 @@ private:
|
||||
collection.Insert(L"Opacity", m_animation);
|
||||
m_root.ImplicitAnimations(collection);
|
||||
|
||||
// 6) Spotlight radius shrinks as opacity increases (expression animation)
|
||||
// Radius of spotlight shrinks as opacity increases.
|
||||
// At opacity zero, it is m_sonarRadius * SonarZoomFactor.
|
||||
// At maximum opacity, it is m_sonarRadius.
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(
|
||||
expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius));
|
||||
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius, FinalAlphaDenominator, m_finalAlphaNumerator));
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_spotlightMaskGradient.StartAnimation(L"EllipseRadius", radiusExpression);
|
||||
// Also animate spotlight geometry radius for visual consistency
|
||||
if (m_circleGeometry)
|
||||
{
|
||||
auto radiusExpression2 = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression2.SetReferenceParameter(L"Root", m_root);
|
||||
radiusExpression2.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression2);
|
||||
}
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression);
|
||||
|
||||
// Composition created successfully
|
||||
return true;
|
||||
}
|
||||
catch (const winrt::hresult_error& e)
|
||||
catch (...)
|
||||
{
|
||||
Logger::error("Failed to create FindMyMouse visual: {}", winrt::to_string(e.message()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -887,27 +760,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateIslandSize()
|
||||
{
|
||||
if (!m_island)
|
||||
return;
|
||||
|
||||
RECT rc{};
|
||||
if (!GetClientRect(m_hwnd, &rc))
|
||||
return;
|
||||
|
||||
const int width = rc.right - rc.left;
|
||||
const int height = rc.bottom - rc.top;
|
||||
|
||||
auto bridge = m_island.SiteBridge();
|
||||
bridge.MoveAndResize(winrt::Windows::Graphics::RectInt32{ 0, 0, width, height });
|
||||
}
|
||||
|
||||
public:
|
||||
void ApplySettings(const FindMyMouseSettings& settings, bool applyToRuntimeObjects)
|
||||
{
|
||||
void ApplySettings(const FindMyMouseSettings& settings, bool applyToRuntimeObjects) {
|
||||
if (!applyToRuntimeObjects)
|
||||
{
|
||||
// Runtime objects not created yet. Just update fields.
|
||||
m_sonarRadius = settings.spotlightRadius;
|
||||
m_sonarRadiusFloat = static_cast<float>(m_sonarRadius);
|
||||
m_backgroundColor = settings.backgroundColor;
|
||||
@@ -916,6 +773,7 @@ public:
|
||||
m_includeWinKey = settings.includeWinKey;
|
||||
m_doNotActivateOnGameMode = settings.doNotActivateOnGameMode;
|
||||
m_fadeDuration = settings.animationDurationMs > 0 ? settings.animationDurationMs : 1;
|
||||
m_finalAlphaNumerator = settings.overlayOpacity;
|
||||
m_sonarZoomFactor = settings.spotlightInitialZoom;
|
||||
m_excludedApps = settings.excludedApps;
|
||||
m_shakeMinimumDistance = settings.shakeMinimumDistance;
|
||||
@@ -924,9 +782,11 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
// Runtime objects already created. Should update in the owner thread.
|
||||
if (m_dispatcherQueueController == nullptr)
|
||||
{
|
||||
Logger::warn("Tried accessing the dispatch queue controller before it was initialized.");
|
||||
// No dispatcher Queue Controller? Means initialization still hasn't run, so settings will be applied then.
|
||||
return;
|
||||
}
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
@@ -934,6 +794,7 @@ public:
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
if (!m_destroyed)
|
||||
{
|
||||
// Runtime objects not created yet. Just update fields.
|
||||
m_sonarRadius = localSettings.spotlightRadius;
|
||||
m_sonarRadiusFloat = static_cast<float>(m_sonarRadius);
|
||||
m_backgroundColor = localSettings.backgroundColor;
|
||||
@@ -942,6 +803,7 @@ public:
|
||||
m_includeWinKey = localSettings.includeWinKey;
|
||||
m_doNotActivateOnGameMode = localSettings.doNotActivateOnGameMode;
|
||||
m_fadeDuration = localSettings.animationDurationMs > 0 ? localSettings.animationDurationMs : 1;
|
||||
m_finalAlphaNumerator = localSettings.overlayOpacity;
|
||||
m_sonarZoomFactor = localSettings.spotlightInitialZoom;
|
||||
m_excludedApps = localSettings.excludedApps;
|
||||
m_shakeMinimumDistance = localSettings.shakeMinimumDistance;
|
||||
@@ -950,41 +812,20 @@ public:
|
||||
UpdateMouseSnooping(); // For the shake mouse activation method
|
||||
|
||||
// Apply new settings to runtime composition objects.
|
||||
if (m_dimColorBrush)
|
||||
{
|
||||
m_dimColorBrush.Color(m_backgroundColor);
|
||||
}
|
||||
if (m_circleShape)
|
||||
{
|
||||
if (auto brush = m_circleShape.FillBrush().try_as<muxc::CompositionColorBrush>())
|
||||
{
|
||||
brush.Color(m_spotlightColor);
|
||||
}
|
||||
}
|
||||
const float scale = static_cast<float>(m_surface.XamlRoot().RasterizationScale());
|
||||
const float rDip = m_sonarRadiusFloat / scale;
|
||||
const float zoom = static_cast<float>(m_sonarZoomFactor);
|
||||
m_spotlightMaskGradient.StopAnimation(L"EllipseRadius");
|
||||
m_spotlightMaskGradient.EllipseCenter({ rDip * zoom, rDip * zoom });
|
||||
if (m_spotlight)
|
||||
{
|
||||
m_spotlight.Size({ rDip * 2 * zoom, rDip * 2 * zoom });
|
||||
m_circleShape.Offset({ rDip * zoom, rDip * zoom });
|
||||
}
|
||||
m_backdrop.Brush().as<winrt::CompositionColorBrush>().Color(m_backgroundColor);
|
||||
m_circleShape.FillBrush().as<winrt::CompositionColorBrush>().Color(m_spotlightColor);
|
||||
m_circleShape.Offset({ m_sonarRadiusFloat * m_sonarZoomFactor, m_sonarRadiusFloat * m_sonarZoomFactor });
|
||||
m_spotlight.Size({ m_sonarRadiusFloat * 2 * m_sonarZoomFactor, m_sonarRadiusFloat * 2 * m_sonarZoomFactor });
|
||||
m_animation.Duration(std::chrono::milliseconds{ m_fadeDuration });
|
||||
m_circleGeometry.StopAnimation(L"Radius");
|
||||
|
||||
// Update animation
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius));
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius, FinalAlphaDenominator, m_finalAlphaNumerator));
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_spotlightMaskGradient.StartAnimation(L"EllipseRadius", radiusExpression);
|
||||
if (m_circleGeometry)
|
||||
{
|
||||
m_circleGeometry.StopAnimation(L"Radius");
|
||||
auto radiusExpression2 = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression2.SetReferenceParameter(L"Root", m_root);
|
||||
radiusExpression2.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression2);
|
||||
}
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression);
|
||||
}
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
@@ -995,27 +836,17 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
muxc::Compositor m_compositor{ nullptr };
|
||||
muxxh::DesktopWindowXamlSource m_island{ nullptr };
|
||||
muxxc::Grid m_surface{ nullptr };
|
||||
|
||||
muxc::ContainerVisual m_root{ nullptr };
|
||||
muxc::CompositionCommitBatch m_batch{ nullptr };
|
||||
muxc::SpriteVisual m_backdrop{ nullptr };
|
||||
// Spotlight shape visuals
|
||||
muxc::CompositionEllipseGeometry m_circleGeometry{ nullptr };
|
||||
muxc::ShapeVisual m_spotlight{ nullptr };
|
||||
muxc::CompositionSpriteShape m_circleShape{ nullptr };
|
||||
// Radial gradient mask components
|
||||
muxc::CompositionMaskBrush m_maskBrush{ nullptr };
|
||||
muxc::CompositionColorBrush m_dimColorBrush{ nullptr };
|
||||
muxc::CompositionRadialGradientBrush m_spotlightMaskGradient{ nullptr };
|
||||
muxc::CompositionColorGradientStop m_maskStopCenter{ nullptr };
|
||||
muxc::CompositionColorGradientStop m_maskStopInner{ nullptr };
|
||||
muxc::CompositionColorGradientStop m_maskStopOuter{ nullptr };
|
||||
winrt::Compositor m_compositor{ nullptr };
|
||||
winrt::Desktop::DesktopWindowTarget m_target{ nullptr };
|
||||
winrt::ContainerVisual m_root{ nullptr };
|
||||
winrt::CompositionEllipseGeometry m_circleGeometry{ nullptr };
|
||||
winrt::ShapeVisual m_spotlight{ nullptr };
|
||||
winrt::CompositionCommitBatch m_batch{ nullptr };
|
||||
winrt::SpriteVisual m_backdrop{ nullptr };
|
||||
winrt::CompositionSpriteShape m_circleShape{ nullptr };
|
||||
winrt::Windows::UI::Color m_backgroundColor = FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR;
|
||||
winrt::Windows::UI::Color m_spotlightColor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR;
|
||||
muxc::ScalarKeyFrameAnimation m_animation{ nullptr };
|
||||
winrt::ScalarKeyFrameAnimation m_animation{ nullptr };
|
||||
};
|
||||
|
||||
template<typename D>
|
||||
@@ -1216,6 +1047,7 @@ struct GdiCrosshairs : GdiSonar<GdiCrosshairs>
|
||||
|
||||
#pragma endregion Super_Sonar_Base_Code
|
||||
|
||||
|
||||
#pragma region Super_Sonar_API
|
||||
|
||||
CompositionSpotlight* m_sonar = nullptr;
|
||||
@@ -1223,6 +1055,7 @@ void FindMyMouseApplySettings(const FindMyMouseSettings& settings)
|
||||
{
|
||||
if (m_sonar != nullptr)
|
||||
{
|
||||
Logger::info("Applying settings.");
|
||||
m_sonar->ApplySettings(settings, true);
|
||||
}
|
||||
}
|
||||
@@ -1231,6 +1064,7 @@ void FindMyMouseDisable()
|
||||
{
|
||||
if (m_sonar != nullptr)
|
||||
{
|
||||
Logger::info("Terminating a sonar instance.");
|
||||
m_sonar->Terminate();
|
||||
}
|
||||
}
|
||||
@@ -1243,6 +1077,7 @@ bool FindMyMouseIsEnabled()
|
||||
// Based on SuperSonar's original wWinMain.
|
||||
int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings)
|
||||
{
|
||||
Logger::info("Starting a sonar instance.");
|
||||
if (m_sonar != nullptr)
|
||||
{
|
||||
Logger::error("A sonar instance was still working when trying to start a new one.");
|
||||
@@ -1257,6 +1092,7 @@ int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings)
|
||||
return 0;
|
||||
}
|
||||
m_sonar = &sonar;
|
||||
Logger::info("Initialized the sonar instance.");
|
||||
|
||||
InitializeWinhookEventIds();
|
||||
|
||||
@@ -1269,6 +1105,7 @@ int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings)
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
Logger::info("Sonar message loop ended.");
|
||||
m_sonar = nullptr;
|
||||
|
||||
return (int)msg.wParam;
|
||||
|
||||
@@ -11,9 +11,9 @@ enum struct FindMyMouseActivationMethod : int
|
||||
};
|
||||
|
||||
constexpr bool FIND_MY_MOUSE_DEFAULT_DO_NOT_ACTIVATE_ON_GAME_MODE = true;
|
||||
// Default colors now include full alpha. Opacity is encoded directly in color alpha (legacy overlay_opacity migrated into A channel)
|
||||
const winrt::Windows::UI::Color FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 0, 0, 0);
|
||||
const winrt::Windows::UI::Color FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 255, 255);
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY = 50;
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS = 100;
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS = 500;
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM = 9;
|
||||
@@ -30,6 +30,7 @@ struct FindMyMouseSettings
|
||||
bool doNotActivateOnGameMode = FIND_MY_MOUSE_DEFAULT_DO_NOT_ACTIVATE_ON_GAME_MODE;
|
||||
winrt::Windows::UI::Color backgroundColor = FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR;
|
||||
winrt::Windows::UI::Color spotlightColor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR;
|
||||
int overlayOpacity = FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY;
|
||||
int spotlightRadius = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS;
|
||||
int animationDurationMs = FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS;
|
||||
int spotlightInitialZoom = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM;
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.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">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
@@ -14,14 +7,6 @@
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>FindMyMouse</RootNamespace>
|
||||
<ProjectName>FindMyMouse</ProjectName>
|
||||
<CppWinRTOptimized>true</CppWinRTOptimized>
|
||||
<CppWinRTEnableComponentProjection>false</CppWinRTEnableComponentProjection>
|
||||
<CppWinRTGenerateWindowsMetadata>false</CppWinRTGenerateWindowsMetadata>
|
||||
<WindowsAppSdkBootstrapInitialize>false</WindowsAppSdkBootstrapInitialize>
|
||||
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
||||
<WindowsAppSDKVerifyTransitiveDependencies>false</WindowsAppSDKVerifyTransitiveDependencies>
|
||||
<!-- Force NuGet to treat this project strictly as packages.config style -->
|
||||
<RestoreProjectStyle>packages.config</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
@@ -45,7 +30,6 @@
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
@@ -95,8 +79,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<!-- Add Generated Files folder so #include <winrt/...> finds projected headers -->
|
||||
<AdditionalIncludeDirectories>$(GeneratedFilesDir);$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;$(MSBuildThisFileDirectory)..\..\..\..\src\;$(MSBuildThisFileDirectory)..\..\..\..\src\modules;$(MSBuildThisFileDirectory)..\..\..\..\src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@@ -115,7 +98,6 @@
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<ClCompile Include="WinHookEventIDs.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
@@ -130,56 +112,16 @@
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<!-- Deduplicate WindowsAppRuntimeAutoInitializer.cpp (added twice via transitive imports causing LNK4042). Remove all then add exactly once. -->
|
||||
<ItemGroup Condition="'$(PkgMicrosoft_WindowsAppSDK)'!=''">
|
||||
<!-- Remove any transitive inclusion first -->
|
||||
<ClCompile Remove="$(PkgMicrosoft_WindowsAppSDK)\include\WindowsAppRuntimeAutoInitializer.cpp" />
|
||||
<!-- Re-add once, but disable PCH because the SDK file doesn't include our pch.h -->
|
||||
<ClCompile Include="$(PkgMicrosoft_WindowsAppSDK)\include\WindowsAppRuntimeAutoInitializer.cpp">
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<Target Name="RemoveManagedWebView2CoreFromNativeOutDir" AfterTargets="Build">
|
||||
<ItemGroup>
|
||||
<_ToDelete Include="$(OutDir)Microsoft.Web.WebView2.Core.dll" />
|
||||
</ItemGroup>
|
||||
<Delete Files="@(_ToDelete)" Condition="Exists('%(Identity)')" />
|
||||
</Target>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<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\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.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.26100.4188\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188\build\Microsoft.Windows.SDK.BuildTools.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets')" />
|
||||
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.Windows.CppWinRT.2.0.240111.5\\build\\native\\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.Windows.CppWinRT.2.0.240111.5\\build\\native\\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.Windows.CppWinRT.2.0.240111.5\\build\\native\\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.Windows.CppWinRT.2.0.240111.5\\build\\native\\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
<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.8.250907003\\build\\native\\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.1.8.250907003\\build\\native\\Microsoft.WindowsAppSDK.props'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.1.8.250907003\\build\\native\\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.1.8.250907003\\build\\native\\Microsoft.WindowsAppSDK.targets'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Base.1.8.250831001\\build\\native\\Microsoft.WindowsAppSDK.Base.props')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Base.1.8.250831001\\build\\native\\Microsoft.WindowsAppSDK.Base.props'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Base.1.8.250831001\\build\\native\\Microsoft.WindowsAppSDK.Base.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Base.1.8.250831001\\build\\native\\Microsoft.WindowsAppSDK.Base.targets'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\\build\\native\\Microsoft.WindowsAppSDK.Foundation.props')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\\build\\native\\Microsoft.WindowsAppSDK.Foundation.props'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\\build\\native\\Microsoft.WindowsAppSDK.Foundation.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\\build\\native\\Microsoft.WindowsAppSDK.Foundation.targets'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\\build\\native\\Microsoft.WindowsAppSDK.WinUI.props')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\\build\\native\\Microsoft.WindowsAppSDK.WinUI.props'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\\build\\native\\Microsoft.WindowsAppSDK.WinUI.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\\build\\native\\Microsoft.WindowsAppSDK.WinUI.targets'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\\build\\native\\Microsoft.WindowsAppSDK.Runtime.props')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\\build\\native\\Microsoft.WindowsAppSDK.Runtime.props'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\\build\\native\\Microsoft.WindowsAppSDK.Runtime.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\\build\\native\\Microsoft.WindowsAppSDK.Runtime.targets'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\\build\\Microsoft.WindowsAppSDK.DWrite.props')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\\build\\Microsoft.WindowsAppSDK.DWrite.props'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\\build\\Microsoft.WindowsAppSDK.DWrite.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\\build\\Microsoft.WindowsAppSDK.DWrite.targets'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\\build\\native\\Microsoft.WindowsAppSDK.InteractiveExperiences.props')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\\build\\native\\Microsoft.WindowsAppSDK.InteractiveExperiences.props'))" />
|
||||
<Error Condition="!Exists('..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\\build\\native\\Microsoft.WindowsAppSDK.InteractiveExperiences.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\\..\\..\\..\\packages\\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\\build\\native\\Microsoft.WindowsAppSDK.InteractiveExperiences.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -18,7 +18,7 @@ namespace
|
||||
const wchar_t JSON_KEY_DO_NOT_ACTIVATE_ON_GAME_MODE[] = L"do_not_activate_on_game_mode";
|
||||
const wchar_t JSON_KEY_BACKGROUND_COLOR[] = L"background_color";
|
||||
const wchar_t JSON_KEY_SPOTLIGHT_COLOR[] = L"spotlight_color";
|
||||
const wchar_t JSON_KEY_OVERLAY_OPACITY[] = L"overlay_opacity"; // legacy only (migrated into color alpha)
|
||||
const wchar_t JSON_KEY_OVERLAY_OPACITY[] = L"overlay_opacity";
|
||||
const wchar_t JSON_KEY_SPOTLIGHT_RADIUS[] = L"spotlight_radius";
|
||||
const wchar_t JSON_KEY_ANIMATION_DURATION_MS[] = L"animation_duration_ms";
|
||||
const wchar_t JSON_KEY_SPOTLIGHT_INITIAL_ZOOM[] = L"spotlight_initial_zoom";
|
||||
@@ -204,22 +204,6 @@ void FindMyMouse::init_settings()
|
||||
}
|
||||
}
|
||||
|
||||
inline static uint8_t LegacyOpacityToAlpha(int overlayOpacityPercent)
|
||||
{
|
||||
if (overlayOpacityPercent < 0)
|
||||
{
|
||||
return 255; // fallback: fully opaque
|
||||
}
|
||||
|
||||
if (overlayOpacityPercent > 100)
|
||||
{
|
||||
overlayOpacityPercent = 100;
|
||||
}
|
||||
|
||||
// Round to nearest integer (0<>255)
|
||||
return static_cast<uint8_t>((overlayOpacityPercent * 255 + 50) / 100);
|
||||
}
|
||||
|
||||
void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
@@ -240,13 +224,14 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
}
|
||||
else
|
||||
{
|
||||
findMyMouseSettings.activationMethod = static_cast<FindMyMouseActivationMethod>(value);
|
||||
}
|
||||
findMyMouseSettings.activationMethod = static_cast<FindMyMouseActivationMethod>(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Invalid Activation Method value");
|
||||
}
|
||||
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -270,49 +255,19 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
Logger::warn("Failed to get 'do not activate on game mode' setting");
|
||||
}
|
||||
// Colors + legacy overlay opacity migration
|
||||
// Desired behavior:
|
||||
// - Old schema: colors stored as RGB (no alpha) + separate overlay_opacity (0-100). We should migrate by applying that opacity as alpha.
|
||||
// - New schema: colors stored as ARGB (alpha embedded). Ignore overlay_opacity even if still present.
|
||||
int legacyOverlayOpacity = -1;
|
||||
bool backgroundColorHadExplicitAlpha = false;
|
||||
bool spotlightColorHadExplicitAlpha = false;
|
||||
try
|
||||
{
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_OVERLAY_OPACITY);
|
||||
int value = static_cast<int>(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE));
|
||||
if (value >= 0 && value <= 100)
|
||||
{
|
||||
legacyOverlayOpacity = value;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// overlay_opacity may not exist anymore
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse background color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_BACKGROUND_COLOR);
|
||||
auto backgroundColorStr = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t a = 255, r, g, b;
|
||||
bool parsed = false;
|
||||
if (checkValidARGB(backgroundColorStr, &a, &r, &g, &b))
|
||||
auto backgroundColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(backgroundColor, &r, &g, &b))
|
||||
{
|
||||
parsed = true;
|
||||
backgroundColorHadExplicitAlpha = true; // New schema with alpha present
|
||||
}
|
||||
else if (checkValidRGB(backgroundColorStr, &r, &g, &b))
|
||||
{
|
||||
a = LegacyOpacityToAlpha(legacyOverlayOpacity);
|
||||
parsed = true; // Old schema (no alpha component)
|
||||
}
|
||||
if (parsed)
|
||||
{
|
||||
findMyMouseSettings.backgroundColor = winrt::Windows::UI::ColorHelper::FromArgb(a, r, g, b);
|
||||
Logger::error("Background color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error("Background color value is invalid. Will use default");
|
||||
findMyMouseSettings.backgroundColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@@ -321,27 +276,17 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse spotlight color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_COLOR);
|
||||
auto spotlightColorStr = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t a = 255, r, g, b;
|
||||
bool parsed = false;
|
||||
if (checkValidARGB(spotlightColorStr, &a, &r, &g, &b))
|
||||
auto spotlightColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(spotlightColor, &r, &g, &b))
|
||||
{
|
||||
parsed = true;
|
||||
spotlightColorHadExplicitAlpha = true;
|
||||
}
|
||||
else if (checkValidRGB(spotlightColorStr, &r, &g, &b))
|
||||
{
|
||||
a = LegacyOpacityToAlpha(legacyOverlayOpacity);
|
||||
parsed = true;
|
||||
}
|
||||
if (parsed)
|
||||
{
|
||||
findMyMouseSettings.spotlightColor = winrt::Windows::UI::ColorHelper::FromArgb(a, r, g, b);
|
||||
Logger::error("Spotlight color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error("Spotlight color value is invalid. Will use default");
|
||||
findMyMouseSettings.spotlightColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@@ -349,6 +294,24 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
Logger::warn("Failed to initialize spotlight color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Overlay Opacity
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_OVERLAY_OPACITY);
|
||||
int value = static_cast<int>(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE));
|
||||
if (value >= 0)
|
||||
{
|
||||
findMyMouseSettings.overlayOpacity = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Invalid Overlay Opacity value");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Overlay Opacity from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Spotlight Radius
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_RADIUS);
|
||||
@@ -529,6 +492,7 @@ void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
m_findMyMouseSettings = findMyMouseSettings;
|
||||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new FindMyMouse();
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK" version="1.8.250907003" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Base" version="1.8.250831001" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Foundation" version="1.8.250906002" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.WinUI" version="1.8.250906003" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Runtime" version="1.8.250907003" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.DWrite" version="1.8.25090401" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.InteractiveExperiences" version="1.8.250906004" targetFramework="native" />
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.2903.40" targetFramework="native" />
|
||||
</packages>
|
||||
</packages>
|
||||
@@ -5,22 +5,15 @@
|
||||
#include <windows.h>
|
||||
#include <strsafe.h>
|
||||
#include <hIdUsage.h>
|
||||
// Required for IUnknown and DECLARE_INTERFACE_* used by interop headers
|
||||
#include <Unknwn.h>
|
||||
|
||||
#ifdef COMPOSITION
|
||||
#include <windows.ui.composition.interop.h>
|
||||
#include <DispatcherQueue.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Microsoft.UI.Composition.h>
|
||||
#include <winrt/Microsoft.UI.h>
|
||||
#include <winrt/Windows.UI.h>
|
||||
#include <winrt/Windows.UI.Composition.Desktop.h>
|
||||
#endif
|
||||
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
@@ -94,21 +94,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static void SetCrosshairsOrientation(CrosshairsOrientation orientation)
|
||||
{
|
||||
if (instance != nullptr)
|
||||
{
|
||||
auto dispatcherQueue = instance->m_dispatcherQueueController.DispatcherQueue();
|
||||
dispatcherQueue.TryEnqueue([orientation]() {
|
||||
if (instance != nullptr)
|
||||
{
|
||||
instance->m_crosshairs_orientation = orientation;
|
||||
instance->UpdateCrosshairsPosition();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
enum class MouseButton
|
||||
{
|
||||
@@ -162,7 +147,6 @@ private:
|
||||
int m_crosshairs_border_size = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE;
|
||||
bool m_crosshairs_is_fixed_length_enabled = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED;
|
||||
int m_crosshairs_fixed_length = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_FIXED_LENGTH;
|
||||
CrosshairsOrientation m_crosshairs_orientation = static_cast<CrosshairsOrientation>(INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_ORIENTATION);
|
||||
float m_crosshairs_opacity = max(0.f, min(1.f, (float)INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_OPACITY / 100.0f));
|
||||
bool m_crosshairs_auto_hide = INCLUSIVE_MOUSE_DEFAULT_AUTO_HIDE;
|
||||
};
|
||||
@@ -302,8 +286,6 @@ void InclusiveCrosshairs::UpdateCrosshairsPosition()
|
||||
float halfPixelAdjustment = m_crosshairs_thickness % 2 == 1 ? 0.5f : 0.0f;
|
||||
float borderSizePadding = m_crosshairs_border_size * 2.f;
|
||||
|
||||
// Left and Right crosshairs (horizontal line)
|
||||
if (m_crosshairs_orientation == CrosshairsOrientation::Both || m_crosshairs_orientation == CrosshairsOrientation::HorizontalOnly)
|
||||
{
|
||||
float leftCrosshairsFullScreenLength = ptCursor.x - ptMonitorUpperLeft.x - m_crosshairs_radius + halfPixelAdjustment * 2.f;
|
||||
float leftCrosshairsLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length : leftCrosshairsFullScreenLength;
|
||||
@@ -312,7 +294,9 @@ void InclusiveCrosshairs::UpdateCrosshairsPosition()
|
||||
m_left_crosshairs_border.Size({ leftCrosshairsBorderLength, m_crosshairs_thickness + borderSizePadding });
|
||||
m_left_crosshairs.Offset({ ptCursor.x - m_crosshairs_radius + halfPixelAdjustment * 2.f, ptCursor.y + halfPixelAdjustment, .0f });
|
||||
m_left_crosshairs.Size({ leftCrosshairsLength, static_cast<float>(m_crosshairs_thickness) });
|
||||
}
|
||||
|
||||
{
|
||||
float rightCrosshairsFullScreenLength = static_cast<float>(ptMonitorBottomRight.x) - ptCursor.x - m_crosshairs_radius;
|
||||
float rightCrosshairsLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length : rightCrosshairsFullScreenLength;
|
||||
float rightCrosshairsBorderLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length + borderSizePadding : rightCrosshairsFullScreenLength + m_crosshairs_border_size;
|
||||
@@ -321,17 +305,7 @@ void InclusiveCrosshairs::UpdateCrosshairsPosition()
|
||||
m_right_crosshairs.Offset({ static_cast<float>(ptCursor.x) + m_crosshairs_radius, ptCursor.y + halfPixelAdjustment, .0f });
|
||||
m_right_crosshairs.Size({ rightCrosshairsLength, static_cast<float>(m_crosshairs_thickness) });
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide horizontal crosshairs by setting size to 0
|
||||
m_left_crosshairs_border.Size({ 0.0f, 0.0f });
|
||||
m_left_crosshairs.Size({ 0.0f, 0.0f });
|
||||
m_right_crosshairs_border.Size({ 0.0f, 0.0f });
|
||||
m_right_crosshairs.Size({ 0.0f, 0.0f });
|
||||
}
|
||||
|
||||
// Top and Bottom crosshairs (vertical line)
|
||||
if (m_crosshairs_orientation == CrosshairsOrientation::Both || m_crosshairs_orientation == CrosshairsOrientation::VerticalOnly)
|
||||
{
|
||||
float topCrosshairsFullScreenLength = ptCursor.y - ptMonitorUpperLeft.y - m_crosshairs_radius + halfPixelAdjustment * 2.f;
|
||||
float topCrosshairsLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length : topCrosshairsFullScreenLength;
|
||||
@@ -340,7 +314,9 @@ void InclusiveCrosshairs::UpdateCrosshairsPosition()
|
||||
m_top_crosshairs_border.Size({ m_crosshairs_thickness + borderSizePadding, topCrosshairsBorderLength });
|
||||
m_top_crosshairs.Offset({ ptCursor.x + halfPixelAdjustment, ptCursor.y - m_crosshairs_radius + halfPixelAdjustment * 2.f, .0f });
|
||||
m_top_crosshairs.Size({ static_cast<float>(m_crosshairs_thickness), topCrosshairsLength });
|
||||
}
|
||||
|
||||
{
|
||||
float bottomCrosshairsFullScreenLength = static_cast<float>(ptMonitorBottomRight.y) - ptCursor.y - m_crosshairs_radius;
|
||||
float bottomCrosshairsLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length : bottomCrosshairsFullScreenLength;
|
||||
float bottomCrosshairsBorderLength = m_crosshairs_is_fixed_length_enabled ? m_crosshairs_fixed_length + borderSizePadding : bottomCrosshairsFullScreenLength + m_crosshairs_border_size;
|
||||
@@ -349,14 +325,6 @@ void InclusiveCrosshairs::UpdateCrosshairsPosition()
|
||||
m_bottom_crosshairs.Offset({ ptCursor.x + halfPixelAdjustment, static_cast<float>(ptCursor.y) + m_crosshairs_radius, .0f });
|
||||
m_bottom_crosshairs.Size({ static_cast<float>(m_crosshairs_thickness), bottomCrosshairsLength });
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide vertical crosshairs by setting size to 0
|
||||
m_top_crosshairs_border.Size({ 0.0f, 0.0f });
|
||||
m_top_crosshairs.Size({ 0.0f, 0.0f });
|
||||
m_bottom_crosshairs_border.Size({ 0.0f, 0.0f });
|
||||
m_bottom_crosshairs.Size({ 0.0f, 0.0f });
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK InclusiveCrosshairs::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept
|
||||
@@ -430,7 +398,6 @@ void InclusiveCrosshairs::ApplySettings(InclusiveCrosshairsSettings& settings, b
|
||||
m_crosshairs_auto_hide = settings.crosshairsAutoHide;
|
||||
m_crosshairs_is_fixed_length_enabled = settings.crosshairsIsFixedLengthEnabled;
|
||||
m_crosshairs_fixed_length = settings.crosshairsFixedLength;
|
||||
m_crosshairs_orientation = settings.crosshairsOrientation;
|
||||
|
||||
if (applyToRunTimeObjects)
|
||||
{
|
||||
@@ -651,11 +618,6 @@ void InclusiveCrosshairsSetExternalControl(bool enabled)
|
||||
InclusiveCrosshairs::SetExternalControl(enabled);
|
||||
}
|
||||
|
||||
void InclusiveCrosshairsSetOrientation(CrosshairsOrientation orientation)
|
||||
{
|
||||
InclusiveCrosshairs::SetCrosshairsOrientation(orientation);
|
||||
}
|
||||
|
||||
int InclusiveCrosshairsMain(HINSTANCE hInstance, InclusiveCrosshairsSettings& settings)
|
||||
{
|
||||
Logger::info("Starting a crosshairs instance.");
|
||||
|
||||
@@ -10,16 +10,8 @@ constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_BORDER_SIZE = 1;
|
||||
constexpr bool INCLUSIVE_MOUSE_DEFAULT_AUTO_HIDE = false;
|
||||
constexpr bool INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED = false;
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_FIXED_LENGTH = 1;
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_ORIENTATION = 0; // 0=Both, 1=Vertical, 2=Horizontal
|
||||
constexpr bool INCLUSIVE_MOUSE_DEFAULT_AUTO_ACTIVATE = false;
|
||||
|
||||
enum struct CrosshairsOrientation : int
|
||||
{
|
||||
Both = 0,
|
||||
VerticalOnly = 1,
|
||||
HorizontalOnly = 2,
|
||||
};
|
||||
|
||||
struct InclusiveCrosshairsSettings
|
||||
{
|
||||
winrt::Windows::UI::Color crosshairsColor = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_COLOR;
|
||||
@@ -31,7 +23,6 @@ struct InclusiveCrosshairsSettings
|
||||
bool crosshairsAutoHide = INCLUSIVE_MOUSE_DEFAULT_AUTO_HIDE;
|
||||
bool crosshairsIsFixedLengthEnabled = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED;
|
||||
int crosshairsFixedLength = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_FIXED_LENGTH;
|
||||
CrosshairsOrientation crosshairsOrientation = static_cast<CrosshairsOrientation>(INCLUSIVE_MOUSE_DEFAULT_CROSSHAIRS_ORIENTATION);
|
||||
bool autoActivate = INCLUSIVE_MOUSE_DEFAULT_AUTO_ACTIVATE;
|
||||
};
|
||||
|
||||
@@ -44,4 +35,3 @@ void InclusiveCrosshairsRequestUpdatePosition();
|
||||
void InclusiveCrosshairsEnsureOn();
|
||||
void InclusiveCrosshairsEnsureOff();
|
||||
void InclusiveCrosshairsSetExternalControl(bool enabled);
|
||||
void InclusiveCrosshairsSetOrientation(CrosshairsOrientation orientation);
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\..\;..\..\..\modules;..\..\..\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
extern void InclusiveCrosshairsRequestUpdatePosition();
|
||||
extern void InclusiveCrosshairsEnsureOn();
|
||||
@@ -31,7 +30,6 @@ namespace
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_AUTO_HIDE[] = L"crosshairs_auto_hide";
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED[] = L"crosshairs_is_fixed_length_enabled";
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_FIXED_LENGTH[] = L"crosshairs_fixed_length";
|
||||
const wchar_t JSON_KEY_CROSSHAIRS_ORIENTATION[] = L"crosshairs_orientation";
|
||||
const wchar_t JSON_KEY_AUTO_ACTIVATE[] = L"auto_activate";
|
||||
const wchar_t JSON_KEY_GLIDE_TRAVEL_SPEED[] = L"gliding_travel_speed";
|
||||
const wchar_t JSON_KEY_GLIDE_DELAY_SPEED[] = L"gliding_delay_speed";
|
||||
@@ -64,9 +62,6 @@ const static wchar_t* MODULE_NAME = L"MousePointerCrosshairs";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"<no description>";
|
||||
|
||||
class MousePointerCrosshairs; // fwd
|
||||
static std::atomic<MousePointerCrosshairs*> g_instance{ nullptr }; // for hook callback
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class MousePointerCrosshairs : public PowertoyModuleIface
|
||||
{
|
||||
@@ -75,11 +70,8 @@ private:
|
||||
bool m_enabled = false;
|
||||
|
||||
// Additional hotkeys (legacy API) to support multiple shortcuts
|
||||
Hotkey m_activationHotkey{}; // Crosshairs toggle
|
||||
Hotkey m_glidingHotkey{}; // Gliding cursor state machine
|
||||
|
||||
// Low-level keyboard hook (Escape to cancel gliding)
|
||||
HHOOK m_keyboardHook = nullptr;
|
||||
Hotkey m_activationHotkey{}; // Crosshairs toggle
|
||||
Hotkey m_glidingHotkey{}; // Gliding cursor state machine
|
||||
|
||||
// Shared state for worker threads (decoupled from this lifetime)
|
||||
struct State
|
||||
@@ -92,7 +84,7 @@ private:
|
||||
int currentYPos{ 0 };
|
||||
int currentXSpeed{ 0 }; // pixels per base window
|
||||
int currentYSpeed{ 0 }; // pixels per base window
|
||||
int xPosSnapshot{ 0 }; // xPos captured at end of horizontal scan
|
||||
int xPosSnapshot{ 0 }; // xPos captured at end of horizontal scan
|
||||
|
||||
// Fractional accumulators to spread movement across 10ms ticks
|
||||
double xFraction{ 0.0 };
|
||||
@@ -100,9 +92,9 @@ private:
|
||||
|
||||
// Speeds represent pixels per 200ms (min 5, max 60 enforced by UI/settings)
|
||||
int fastHSpeed{ 30 }; // pixels per base window
|
||||
int slowHSpeed{ 5 }; // pixels per base window
|
||||
int slowHSpeed{ 5 }; // pixels per base window
|
||||
int fastVSpeed{ 30 }; // pixels per base window
|
||||
int slowVSpeed{ 5 }; // pixels per base window
|
||||
int slowVSpeed{ 5 }; // pixels per base window
|
||||
};
|
||||
|
||||
std::shared_ptr<State> m_state;
|
||||
@@ -128,16 +120,13 @@ public:
|
||||
LoggerHelpers::init_logger(MODULE_NAME, L"ModuleInterface", LogSettings::mousePointerCrosshairsLoggerName);
|
||||
m_state = std::make_shared<State>();
|
||||
init_settings();
|
||||
g_instance.store(this, std::memory_order_release);
|
||||
};
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
UninstallKeyboardHook();
|
||||
StopXTimer();
|
||||
StopYTimer();
|
||||
g_instance.store(nullptr, std::memory_order_release);
|
||||
// Release shared state so worker threads (if any) exit when weak_ptr lock fails
|
||||
m_state.reset();
|
||||
delete this;
|
||||
@@ -207,7 +196,6 @@ public:
|
||||
{
|
||||
m_enabled = false;
|
||||
Trace::EnableMousePointerCrosshairs(false);
|
||||
UninstallKeyboardHook();
|
||||
StopXTimer();
|
||||
StopYTimer();
|
||||
m_glideState = 0;
|
||||
@@ -232,7 +220,7 @@ public:
|
||||
if (buffer && buffer_size >= 2)
|
||||
{
|
||||
buffer[0] = m_activationHotkey; // Crosshairs toggle
|
||||
buffer[1] = m_glidingHotkey; // Gliding cursor toggle
|
||||
buffer[1] = m_glidingHotkey; // Gliding cursor toggle
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
@@ -268,27 +256,6 @@ private:
|
||||
SendInput(2, inputs, sizeof(INPUT));
|
||||
}
|
||||
|
||||
// Cancel gliding without performing the final click (Escape handling)
|
||||
void CancelGliding()
|
||||
{
|
||||
int state = m_glideState.load();
|
||||
if (state == 0)
|
||||
{
|
||||
return; // nothing to cancel
|
||||
}
|
||||
StopXTimer();
|
||||
StopYTimer();
|
||||
m_glideState = 0;
|
||||
InclusiveCrosshairsEnsureOff();
|
||||
InclusiveCrosshairsSetExternalControl(false);
|
||||
if (auto s = m_state)
|
||||
{
|
||||
s->xFraction = 0.0;
|
||||
s->yFraction = 0.0;
|
||||
}
|
||||
Logger::debug("Gliding cursor cancelled via Escape key");
|
||||
}
|
||||
|
||||
// Stateless helpers operating on shared State
|
||||
static void PositionCursorX(const std::shared_ptr<State>& s)
|
||||
{
|
||||
@@ -431,14 +398,10 @@ private:
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// For detect for cancel key
|
||||
InstallKeyboardHook();
|
||||
// Ensure crosshairs on (do not toggle off if already on)
|
||||
InclusiveCrosshairsEnsureOn();
|
||||
// Disable internal mouse hook so we control position updates explicitly
|
||||
InclusiveCrosshairsSetExternalControl(true);
|
||||
// Override crosshairs to show both for Gliding Cursor
|
||||
InclusiveCrosshairsSetOrientation(CrosshairsOrientation::Both);
|
||||
|
||||
s->currentXPos = 0;
|
||||
s->currentXSpeed = s->fastHSpeed;
|
||||
@@ -481,15 +444,12 @@ private:
|
||||
case 4:
|
||||
default:
|
||||
{
|
||||
UninstallKeyboardHook();
|
||||
// Stop vertical, click, turn crosshairs off, re-enable internal tracking, reset state
|
||||
StopYTimer();
|
||||
m_glideState = 0;
|
||||
LeftClick();
|
||||
InclusiveCrosshairsEnsureOff();
|
||||
InclusiveCrosshairsSetExternalControl(false);
|
||||
// Restore original crosshairs orientation setting
|
||||
InclusiveCrosshairsSetOrientation(m_inclusiveCrosshairsSettings.crosshairsOrientation);
|
||||
s->xFraction = 0.0;
|
||||
s->yFraction = 0.0;
|
||||
break;
|
||||
@@ -497,51 +457,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// Low-level keyboard hook procedures
|
||||
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (nCode == HC_ACTION)
|
||||
{
|
||||
const KBDLLHOOKSTRUCT* kb = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||
if (kb && kb->vkCode == VK_ESCAPE && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
|
||||
{
|
||||
if (auto inst = g_instance.load(std::memory_order_acquire))
|
||||
{
|
||||
if (inst->m_enabled && inst->m_glideState.load() != 0)
|
||||
{
|
||||
inst->UninstallKeyboardHook();
|
||||
inst->CancelGliding();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not swallow Escape; pass it through
|
||||
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
void InstallKeyboardHook()
|
||||
{
|
||||
if (m_keyboardHook)
|
||||
{
|
||||
return; // already installed
|
||||
}
|
||||
m_keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, m_hModule, 0);
|
||||
if (!m_keyboardHook)
|
||||
{
|
||||
Logger::error("Failed to install low-level keyboard hook for MousePointerCrosshairs (Escape cancel). GetLastError={}.", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
void UninstallKeyboardHook()
|
||||
{
|
||||
if (m_keyboardHook)
|
||||
{
|
||||
UnhookWindowsHookEx(m_keyboardHook);
|
||||
m_keyboardHook = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the settings file.
|
||||
void init_settings()
|
||||
{
|
||||
@@ -560,287 +475,264 @@ private:
|
||||
|
||||
void parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
// Refactored JSON parsing: uses inline try-catch blocks for each property for clarity and error handling
|
||||
// TODO: refactor to use common/utils/json.h instead
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
InclusiveCrosshairsSettings inclusiveCrosshairsSettings;
|
||||
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
auto propertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES);
|
||||
|
||||
// Parse activation hotkey
|
||||
try
|
||||
{
|
||||
auto jsonHotkeyObject = propertiesObject.GetNamedObject(JSON_KEY_ACTIVATION_SHORTCUT);
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(jsonHotkeyObject);
|
||||
m_activationHotkey.win = hotkey.win_pressed();
|
||||
m_activationHotkey.ctrl = hotkey.ctrl_pressed();
|
||||
m_activationHotkey.shift = hotkey.shift_pressed();
|
||||
m_activationHotkey.alt = hotkey.alt_pressed();
|
||||
m_activationHotkey.key = static_cast<unsigned char>(hotkey.get_code());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Mouse Pointer Crosshairs activation shortcut");
|
||||
}
|
||||
// Parse primary activation HotKey (for centralized hook)
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ACTIVATION_SHORTCUT);
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(jsonPropertiesObject);
|
||||
|
||||
// Parse gliding cursor hotkey
|
||||
try
|
||||
// Map to legacy Hotkey for multi-hotkey API
|
||||
m_activationHotkey.win = hotkey.win_pressed();
|
||||
m_activationHotkey.ctrl = hotkey.ctrl_pressed();
|
||||
m_activationHotkey.shift = hotkey.shift_pressed();
|
||||
m_activationHotkey.alt = hotkey.alt_pressed();
|
||||
m_activationHotkey.key = static_cast<unsigned char>(hotkey.get_code());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Mouse Pointer Crosshairs activation shortcut");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Gliding Cursor HotKey
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_GLIDING_ACTIVATION_SHORTCUT);
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(jsonPropertiesObject);
|
||||
m_glidingHotkey.win = hotkey.win_pressed();
|
||||
m_glidingHotkey.ctrl = hotkey.ctrl_pressed();
|
||||
m_glidingHotkey.shift = hotkey.shift_pressed();
|
||||
m_glidingHotkey.alt = hotkey.alt_pressed();
|
||||
m_glidingHotkey.key = static_cast<unsigned char>(hotkey.get_code());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// note that this is also defined in src\settings-ui\Settings.UI.Library\MousePointerCrosshairsProperties.cs, DefaultGlidingCursorActivationShortcut
|
||||
// both need to be kept in sync!
|
||||
Logger::warn("Failed to initialize Gliding Cursor activation shortcut. Using default Win+Alt+.");
|
||||
m_glidingHotkey.win = true;
|
||||
m_glidingHotkey.alt = true;
|
||||
m_glidingHotkey.ctrl = false;
|
||||
m_glidingHotkey.shift = false;
|
||||
m_glidingHotkey.key = VK_OEM_PERIOD;
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Opacity
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_OPACITY);
|
||||
int value = static_cast<uint8_t>(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE));
|
||||
if (value >= 0)
|
||||
{
|
||||
auto jsonHotkeyObject = propertiesObject.GetNamedObject(JSON_KEY_GLIDING_ACTIVATION_SHORTCUT);
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(jsonHotkeyObject);
|
||||
m_glidingHotkey.win = hotkey.win_pressed();
|
||||
m_glidingHotkey.ctrl = hotkey.ctrl_pressed();
|
||||
m_glidingHotkey.shift = hotkey.shift_pressed();
|
||||
m_glidingHotkey.alt = hotkey.alt_pressed();
|
||||
m_glidingHotkey.key = static_cast<unsigned char>(hotkey.get_code());
|
||||
inclusiveCrosshairsSettings.crosshairsOpacity = value;
|
||||
}
|
||||
catch (...)
|
||||
else
|
||||
{
|
||||
Logger::warn("Failed to initialize Gliding Cursor activation shortcut. Using default Win+Alt+.");
|
||||
m_glidingHotkey.win = true;
|
||||
m_glidingHotkey.alt = true;
|
||||
m_glidingHotkey.ctrl = false;
|
||||
m_glidingHotkey.shift = false;
|
||||
m_glidingHotkey.key = VK_OEM_PERIOD;
|
||||
}
|
||||
|
||||
// Parse individual properties with error handling and defaults
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_opacity"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_opacity");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsOpacity = static_cast<int>(propertyObj.GetNamedNumber(L"value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default value */ }
|
||||
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_radius"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_radius");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsRadius = static_cast<int>(propertyObj.GetNamedNumber(L"value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default value */ }
|
||||
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_thickness"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_thickness");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsThickness = static_cast<int>(propertyObj.GetNamedNumber(L"value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default value */ }
|
||||
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_border_size"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_border_size");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsBorderSize = static_cast<int>(propertyObj.GetNamedNumber(L"value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default value */ }
|
||||
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_fixed_length"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_fixed_length");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsFixedLength = static_cast<int>(propertyObj.GetNamedNumber(L"value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default value */ }
|
||||
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_auto_hide"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_auto_hide");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsAutoHide = propertyObj.GetNamedBoolean(L"value");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default value */ }
|
||||
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_is_fixed_length_enabled"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_is_fixed_length_enabled");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsIsFixedLengthEnabled = propertyObj.GetNamedBoolean(L"value");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default value */ }
|
||||
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"auto_activate"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"auto_activate");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
inclusiveCrosshairsSettings.autoActivate = propertyObj.GetNamedBoolean(L"value");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default value */ }
|
||||
|
||||
// Parse orientation with validation - this fixes the original issue!
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_orientation"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_orientation");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
int orientationValue = static_cast<int>(propertyObj.GetNamedNumber(L"value"));
|
||||
if (orientationValue >= 0 && orientationValue <= 2)
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsOrientation = static_cast<CrosshairsOrientation>(orientationValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default value (Both = 0) */ }
|
||||
|
||||
// Parse colors with validation
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_color"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_color");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
std::wstring crosshairsColorValue = std::wstring(propertyObj.GetNamedString(L"value").c_str());
|
||||
uint8_t r, g, b;
|
||||
if (checkValidRGB(crosshairsColorValue, &r, &g, &b))
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default color */ }
|
||||
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"crosshairs_border_color"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"crosshairs_border_color");
|
||||
if (propertyObj.HasKey(L"value"))
|
||||
{
|
||||
std::wstring borderColorValue = std::wstring(propertyObj.GetNamedString(L"value").c_str());
|
||||
uint8_t r, g, b;
|
||||
if (checkValidRGB(borderColorValue, &r, &g, &b))
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsBorderColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { /* Use default border color */ }
|
||||
|
||||
// Parse speed settings with validation
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"gliding_travel_speed"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"gliding_travel_speed");
|
||||
if (propertyObj.HasKey(L"value") && m_state)
|
||||
{
|
||||
int travelSpeedValue = static_cast<int>(propertyObj.GetNamedNumber(L"value"));
|
||||
if (travelSpeedValue >= 5 && travelSpeedValue <= 60)
|
||||
{
|
||||
m_state->fastHSpeed = travelSpeedValue;
|
||||
m_state->fastVSpeed = travelSpeedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clamp to valid range
|
||||
int clampedValue = travelSpeedValue;
|
||||
if (clampedValue < 5) clampedValue = 5;
|
||||
if (clampedValue > 60) clampedValue = 60;
|
||||
m_state->fastHSpeed = clampedValue;
|
||||
m_state->fastVSpeed = clampedValue;
|
||||
Logger::warn("Travel speed value out of range, clamped to valid range");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (m_state)
|
||||
{
|
||||
m_state->fastHSpeed = 25;
|
||||
m_state->fastVSpeed = 25;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (propertiesObject.HasKey(L"gliding_delay_speed"))
|
||||
{
|
||||
auto propertyObj = propertiesObject.GetNamedObject(L"gliding_delay_speed");
|
||||
if (propertyObj.HasKey(L"value") && m_state)
|
||||
{
|
||||
int delaySpeedValue = static_cast<int>(propertyObj.GetNamedNumber(L"value"));
|
||||
if (delaySpeedValue >= 5 && delaySpeedValue <= 60)
|
||||
{
|
||||
m_state->slowHSpeed = delaySpeedValue;
|
||||
m_state->slowVSpeed = delaySpeedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clamp to valid range
|
||||
int clampedValue = delaySpeedValue;
|
||||
if (clampedValue < 5) clampedValue = 5;
|
||||
if (clampedValue > 60) clampedValue = 60;
|
||||
m_state->slowHSpeed = clampedValue;
|
||||
m_state->slowVSpeed = clampedValue;
|
||||
Logger::warn("Delay speed value out of range, clamped to valid range");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (m_state)
|
||||
{
|
||||
m_state->slowHSpeed = 5;
|
||||
m_state->slowVSpeed = 5;
|
||||
}
|
||||
throw std::runtime_error("Invalid Opacity value");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Error parsing some MousePointerCrosshairs properties. Using defaults for failed properties.");
|
||||
Logger::warn("Failed to initialize Opacity from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse crosshairs color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_COLOR);
|
||||
auto crosshairsColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(crosshairsColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Crosshairs color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize crosshairs color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Radius
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_RADIUS);
|
||||
int value = static_cast<int>(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE));
|
||||
if (value >= 0)
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsRadius = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Invalid Radius value");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Radius from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Thickness
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_THICKNESS);
|
||||
int value = static_cast<int>(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE));
|
||||
if (value >= 0)
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsThickness = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Invalid Thickness value");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Thickness from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse crosshairs border color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_BORDER_COLOR);
|
||||
auto crosshairsBorderColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(crosshairsBorderColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Crosshairs border color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsBorderColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize crosshairs border color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse border size
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_BORDER_SIZE);
|
||||
int value = static_cast<int>(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE));
|
||||
if (value >= 0)
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsBorderSize = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Invalid Border Color value");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize border color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse auto hide
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_AUTO_HIDE);
|
||||
inclusiveCrosshairsSettings.crosshairsAutoHide = jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize auto hide from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse whether the fixed length is enabled
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_IS_FIXED_LENGTH_ENABLED);
|
||||
bool value = jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE);
|
||||
inclusiveCrosshairsSettings.crosshairsIsFixedLengthEnabled = value;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize fixed length enabled from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse fixed length
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIRS_FIXED_LENGTH);
|
||||
int value = static_cast<int>(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE));
|
||||
if (value >= 0)
|
||||
{
|
||||
inclusiveCrosshairsSettings.crosshairsFixedLength = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Invalid Fixed Length value");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize fixed length from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse auto activate
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_AUTO_ACTIVATE);
|
||||
inclusiveCrosshairsSettings.autoActivate = jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize auto activate from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Travel speed (fast speed mapping)
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_GLIDE_TRAVEL_SPEED);
|
||||
int value = static_cast<int>(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE));
|
||||
if (value >= 5 && value <= 60)
|
||||
{
|
||||
m_state->fastHSpeed = value;
|
||||
m_state->fastVSpeed = value;
|
||||
}
|
||||
else if (value < 5)
|
||||
{
|
||||
m_state->fastHSpeed = 5; m_state->fastVSpeed = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state->fastHSpeed = 60; m_state->fastVSpeed = 60;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize gliding travel speed from settings. Using default 25.");
|
||||
if (m_state)
|
||||
{
|
||||
m_state->fastHSpeed = 25;
|
||||
m_state->fastVSpeed = 25;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Delay speed (slow speed mapping)
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_GLIDE_DELAY_SPEED);
|
||||
int value = static_cast<int>(jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE));
|
||||
if (value >= 5 && value <= 60)
|
||||
{
|
||||
m_state->slowHSpeed = value;
|
||||
m_state->slowVSpeed = value;
|
||||
}
|
||||
else if (value < 5)
|
||||
{
|
||||
m_state->slowHSpeed = 5; m_state->slowVSpeed = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state->slowHSpeed = 60; m_state->slowVSpeed = 60;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize gliding delay speed from settings. Using default 5.");
|
||||
if (m_state)
|
||||
{
|
||||
m_state->slowHSpeed = 5;
|
||||
m_state->slowVSpeed = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -848,7 +740,6 @@ private:
|
||||
Logger::info("Mouse Pointer Crosshairs settings are empty");
|
||||
}
|
||||
|
||||
// Set default hotkeys if not configured
|
||||
if (m_activationHotkey.key == 0)
|
||||
{
|
||||
m_activationHotkey.win = true;
|
||||
@@ -865,7 +756,6 @@ private:
|
||||
m_glidingHotkey.shift = false;
|
||||
m_glidingHotkey.key = VK_OEM_PERIOD;
|
||||
}
|
||||
|
||||
m_inclusiveCrosshairsSettings = inclusiveCrosshairsSettings;
|
||||
}
|
||||
};
|
||||
|
||||
1162
src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs
Normal file
@@ -0,0 +1,284 @@
|
||||
// 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.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
|
||||
// <summary>
|
||||
// Initialization and clean up.
|
||||
// </summary>
|
||||
// <history>
|
||||
// 2008 created by Truong Do (ductdo).
|
||||
// 2009-... modified by Truong Do (TruongDo).
|
||||
// 2023- Included in PowerToys.
|
||||
// </history>
|
||||
using Microsoft.Win32;
|
||||
using MouseWithoutBorders.Class;
|
||||
using MouseWithoutBorders.Core;
|
||||
using MouseWithoutBorders.Form;
|
||||
using Windows.UI.Input.Preview.Injection;
|
||||
|
||||
using Thread = MouseWithoutBorders.Core.Thread;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
{
|
||||
internal partial class Common
|
||||
{
|
||||
private static bool initDone;
|
||||
internal static int REOPEN_WHEN_WSAECONNRESET = -10054;
|
||||
internal static int REOPEN_WHEN_HOTKEY = -10055;
|
||||
internal static int PleaseReopenSocket;
|
||||
internal static bool ReopenSocketDueToReadError;
|
||||
|
||||
internal static DateTime LastResumeSuspendTime { get; set; } = DateTime.UtcNow;
|
||||
|
||||
internal static bool InitDone
|
||||
{
|
||||
get => Common.initDone;
|
||||
set => Common.initDone = value;
|
||||
}
|
||||
|
||||
internal static void UpdateMachineTimeAndID()
|
||||
{
|
||||
Common.MachineName = Common.MachineName.Trim();
|
||||
_ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
|
||||
}
|
||||
|
||||
private static void InitializeMachinePoolFromSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
MachineInf[] info = MachinePoolHelpers.LoadMachineInfoFromMachinePoolStringSetting(Setting.Values.MachinePoolString);
|
||||
for (int i = 0; i < info.Length; i++)
|
||||
{
|
||||
info[i].Name = info[i].Name.Trim();
|
||||
}
|
||||
|
||||
MachineStuff.MachinePool.Initialize(info);
|
||||
MachineStuff.MachinePool.ResetIPAddressesForDeadMachines(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log(ex);
|
||||
MachineStuff.MachinePool.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SetupMachineNameAndID()
|
||||
{
|
||||
try
|
||||
{
|
||||
GetMachineName();
|
||||
DesMachineID = MachineStuff.NewDesMachineID = MachineID;
|
||||
|
||||
// MessageBox.Show(machineID.ToString(CultureInfo.CurrentCulture)); // For test
|
||||
InitializeMachinePoolFromSettings();
|
||||
|
||||
Common.MachineName = Common.MachineName.Trim();
|
||||
_ = MachineStuff.MachinePool.LearnMachine(Common.MachineName);
|
||||
_ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
|
||||
|
||||
MachineStuff.UpdateMachinePoolStringSetting();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
_ = Helper.GetUserName();
|
||||
Common.GeneratedKey = true;
|
||||
|
||||
try
|
||||
{
|
||||
Common.MyKey = Setting.Values.MyKey;
|
||||
int tmp = Setting.Values.MyKeyDaysToExpire;
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
Common.KeyCorrupted = true;
|
||||
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
|
||||
Logger.Log(e.Message);
|
||||
}
|
||||
catch (CryptographicException e)
|
||||
{
|
||||
Common.KeyCorrupted = true;
|
||||
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
|
||||
Logger.Log(e.Message);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
InputSimulation.Injector = InputInjector.TryCreate();
|
||||
if (InputSimulation.Injector != null)
|
||||
{
|
||||
InputSimulation.MoveMouseRelative(0, 0);
|
||||
NativeMethods.InjectMouseInputAvailable = true;
|
||||
}
|
||||
}
|
||||
catch (EntryPointNotFoundException)
|
||||
{
|
||||
NativeMethods.InjectMouseInputAvailable = false;
|
||||
Logger.Log($"{nameof(NativeMethods.InjectMouseInputAvailable)} = false");
|
||||
}
|
||||
|
||||
bool dummy = Setting.Values.DrawMouseEx;
|
||||
Is64bitOS = IntPtr.Size == 8;
|
||||
tcpPort = Setting.Values.TcpPort;
|
||||
GetScreenConfig();
|
||||
PackageSent = new PackageMonitor(0);
|
||||
PackageReceived = new PackageMonitor(0);
|
||||
SetupMachineNameAndID();
|
||||
InitEncryption();
|
||||
CreateHelperThreads();
|
||||
|
||||
SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);
|
||||
NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
|
||||
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
|
||||
PleaseReopenSocket = 9;
|
||||
/* TODO: Telemetry for the matrix? */
|
||||
}
|
||||
|
||||
private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
|
||||
{
|
||||
Helper.WndProcCounter++;
|
||||
|
||||
if (e.Mode is PowerModes.Resume or PowerModes.Suspend)
|
||||
{
|
||||
Logger.TelemetryLogTrace($"{nameof(SystemEvents_PowerModeChanged)}: {e.Mode}", SeverityLevel.Information);
|
||||
LastResumeSuspendTime = DateTime.UtcNow;
|
||||
MachineStuff.SwitchToMultipleMode(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateHelperThreads()
|
||||
{
|
||||
// NOTE(@yuyoyuppe): service crashes while trying to obtain this info, disabling.
|
||||
/*
|
||||
Thread watchDogThread = new(new ThreadStart(WatchDogThread), nameof(WatchDogThread));
|
||||
watchDogThread.Priority = ThreadPriority.Highest;
|
||||
watchDogThread.Start();
|
||||
*/
|
||||
|
||||
helper = new Thread(new ThreadStart(Helper.HelperThread), "Helper Thread");
|
||||
helper.SetApartmentState(ApartmentState.STA);
|
||||
helper.Start();
|
||||
}
|
||||
|
||||
private static void AskHelperThreadsToExit(int waitTime)
|
||||
{
|
||||
Helper.signalHelperToExit = true;
|
||||
Helper.signalWatchDogToExit = true;
|
||||
_ = EvSwitch.Set();
|
||||
|
||||
int c = 0;
|
||||
if (helper != null && c < waitTime)
|
||||
{
|
||||
while (Helper.signalHelperToExit)
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
||||
helper = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Cleanup()
|
||||
{
|
||||
try
|
||||
{
|
||||
SendByeBye();
|
||||
|
||||
// UnhookClipboard();
|
||||
AskHelperThreadsToExit(500);
|
||||
MainForm.NotifyIcon.Visible = false;
|
||||
MainForm.NotifyIcon.Dispose();
|
||||
CloseAllFormsAndHooks();
|
||||
|
||||
DoSomethingInUIThread(() =>
|
||||
{
|
||||
Sk?.Close(true);
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static long lastReleaseAllKeysCall;
|
||||
|
||||
internal static void ReleaseAllKeys()
|
||||
{
|
||||
if (Math.Abs(GetTick() - lastReleaseAllKeysCall) < 2000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lastReleaseAllKeysCall = GetTick();
|
||||
|
||||
KEYBDDATA kd;
|
||||
kd.dwFlags = (int)LLKHF.UP;
|
||||
|
||||
VK[] keys = new VK[]
|
||||
{
|
||||
VK.LSHIFT, VK.LCONTROL, VK.LMENU, VK.LWIN, VK.RSHIFT,
|
||||
VK.RCONTROL, VK.RMENU, VK.RWIN, VK.SHIFT, VK.MENU, VK.CONTROL,
|
||||
};
|
||||
|
||||
Logger.LogDebug("***** ReleaseAllKeys has been called! *****:");
|
||||
|
||||
foreach (VK vk in keys)
|
||||
{
|
||||
if ((NativeMethods.GetAsyncKeyState((IntPtr)vk) & 0x8000) != 0)
|
||||
{
|
||||
Logger.LogDebug(vk.ToString() + " is down, release it...");
|
||||
Hook?.ResetLastSwitchKeys(); // Sticky key can turn ALL PC mode on (CtrlCtrlCtrl)
|
||||
kd.wVk = (int)vk;
|
||||
InputSimulation.SendKey(kd);
|
||||
Hook?.ResetLastSwitchKeys();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
|
||||
{
|
||||
Logger.LogDebug("NetworkAvailabilityEventArgs.IsAvailable: " + e.IsAvailable.ToString(CultureInfo.InvariantCulture));
|
||||
Helper.WndProcCounter++;
|
||||
ScheduleReopenSocketsDueToNetworkChanges(!e.IsAvailable);
|
||||
}
|
||||
|
||||
private static void ScheduleReopenSocketsDueToNetworkChanges(bool closeSockets = true)
|
||||
{
|
||||
if (closeSockets)
|
||||
{
|
||||
// Slept/hibernated machine may still have the sockets' status as Connected:( (unchanged) so it would not re-connect after a timeout when waking up.
|
||||
// Closing the sockets when it is going to sleep/hibernate will trigger the reconnection faster when it wakes up.
|
||||
DoSomethingInUIThread(
|
||||
() =>
|
||||
{
|
||||
SocketStuff s = Sk;
|
||||
Sk = null;
|
||||
s?.Close(false);
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
if (!Common.IsMyDesktopActive())
|
||||
{
|
||||
PleaseReopenSocket = 0;
|
||||
}
|
||||
else if (PleaseReopenSocket != 10)
|
||||
{
|
||||
PleaseReopenSocket = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
internal static string ActiveDesktop => Common.activeDesktop;
|
||||
|
||||
internal static void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
|
||||
private static void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
|
||||
{
|
||||
GetScreenConfig();
|
||||
}
|
||||
@@ -340,7 +340,7 @@ namespace MouseWithoutBorders
|
||||
Setting.Values.LastX = JUST_GOT_BACK_FROM_SCREEN_SAVER;
|
||||
if (cleanupIfExit)
|
||||
{
|
||||
InitAndCleanup.Cleanup();
|
||||
Common.Cleanup();
|
||||
}
|
||||
|
||||
Process.GetCurrentProcess().KillProcess();
|
||||
|
||||
@@ -33,7 +33,6 @@ using MouseWithoutBorders.Class;
|
||||
using MouseWithoutBorders.Core;
|
||||
using MouseWithoutBorders.Exceptions;
|
||||
|
||||
using Clipboard = MouseWithoutBorders.Core.Clipboard;
|
||||
using Thread = MouseWithoutBorders.Core.Thread;
|
||||
|
||||
// Log is enough
|
||||
@@ -91,8 +90,8 @@ namespace MouseWithoutBorders
|
||||
private static FrmMatrix matrixForm;
|
||||
private static FrmInputCallback inputCallbackForm;
|
||||
private static FrmAbout aboutForm;
|
||||
private static Thread helper;
|
||||
#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
|
||||
internal static Thread helper;
|
||||
internal static int screenWidth;
|
||||
internal static int screenHeight;
|
||||
#pragma warning restore SA1307
|
||||
@@ -122,9 +121,7 @@ namespace MouseWithoutBorders
|
||||
internal static int switchCount;
|
||||
#pragma warning restore SA1307
|
||||
private static long lastReconnectByHotKeyTime;
|
||||
#pragma warning disable SA1307 // Accessible fields should begin with upper-case names
|
||||
internal static int tcpPort;
|
||||
#pragma warning restore SA1307
|
||||
private static int tcpPort;
|
||||
private static bool secondOpenSocketTry;
|
||||
private static string binaryName;
|
||||
|
||||
@@ -213,7 +210,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
internal static bool Is64bitOS
|
||||
{
|
||||
get; set;
|
||||
get; private set;
|
||||
|
||||
// set { Common.is64bitOS = value; }
|
||||
}
|
||||
@@ -614,7 +611,7 @@ namespace MouseWithoutBorders
|
||||
}
|
||||
* */
|
||||
|
||||
internal static void SendByeBye()
|
||||
private static void SendByeBye()
|
||||
{
|
||||
Logger.LogDebug($"{nameof(SendByeBye)}");
|
||||
SendPackage(ID.ALL, PackageType.ByeBye);
|
||||
@@ -728,7 +725,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
internal static void SendImage(string machine, string file)
|
||||
{
|
||||
Clipboard.LastDragDropFile = file;
|
||||
LastDragDropFile = file;
|
||||
|
||||
// Send ClipboardCapture
|
||||
if (machine.Equals("All", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -747,7 +744,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
internal static void SendImage(ID src, string file)
|
||||
{
|
||||
Clipboard.LastDragDropFile = file;
|
||||
LastDragDropFile = file;
|
||||
|
||||
// Send ClipboardCapture
|
||||
SendPackage(src, PackageType.ClipboardCapture);
|
||||
@@ -1294,7 +1291,7 @@ namespace MouseWithoutBorders
|
||||
});
|
||||
}
|
||||
|
||||
internal static string GetMyStorageDir()
|
||||
private static string GetMyStorageDir()
|
||||
{
|
||||
string st = string.Empty;
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ using MouseWithoutBorders.Core;
|
||||
|
||||
using SystemClipboard = System.Windows.Forms.Clipboard;
|
||||
#if !MM_HELPER
|
||||
using Clipboard = MouseWithoutBorders.Core.Clipboard;
|
||||
using Thread = MouseWithoutBorders.Core.Thread;
|
||||
#endif
|
||||
|
||||
@@ -160,7 +159,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
public void SendClipboardData(ByteArrayOrString data, bool isFilePath)
|
||||
{
|
||||
_ = Clipboard.CheckClipboardEx(data, isFilePath);
|
||||
_ = Common.CheckClipboardEx(data, isFilePath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -579,7 +579,7 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
Common.ShowToolTip("Reconnecting...", 2000);
|
||||
Common.LastReconnectByHotKeyTime = Common.GetTick();
|
||||
InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_HOTKEY;
|
||||
Common.PleaseReopenSocket = Common.REOPEN_WHEN_HOTKEY;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -632,7 +632,7 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
// Common.DoSomethingInUIThread(delegate()
|
||||
{
|
||||
InitAndCleanup.ReleaseAllKeys();
|
||||
Common.ReleaseAllKeys();
|
||||
}
|
||||
|
||||
// );
|
||||
|
||||
@@ -407,7 +407,7 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
ResetModifiersState(Setting.Values.HotKeyLockMachine);
|
||||
eatKey = true;
|
||||
InitAndCleanup.ReleaseAllKeys();
|
||||
Common.ReleaseAllKeys();
|
||||
_ = NativeMethods.LockWorkStation();
|
||||
}
|
||||
}
|
||||
@@ -439,7 +439,7 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
ctrlDown = altDown = false;
|
||||
eatKey = true;
|
||||
InitAndCleanup.ReleaseAllKeys();
|
||||
Common.ReleaseAllKeys();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -449,7 +449,7 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
winDown = false;
|
||||
eatKey = true;
|
||||
InitAndCleanup.ReleaseAllKeys();
|
||||
Common.ReleaseAllKeys();
|
||||
uint rv = NativeMethods.LockWorkStation();
|
||||
Logger.LogDebug("LockWorkStation returned " + rv.ToString(CultureInfo.CurrentCulture));
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace MouseWithoutBorders.Class
|
||||
_ = Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
InitAndCleanup.Init();
|
||||
Common.Init();
|
||||
Core.Helper.WndProcCounter++;
|
||||
|
||||
var formScreen = new FrmScreen();
|
||||
@@ -314,7 +314,7 @@ namespace MouseWithoutBorders.Class
|
||||
MachineStuff.UpdateMachinePoolStringSetting();
|
||||
|
||||
SocketStuff.InvalidKeyFound = false;
|
||||
InitAndCleanup.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSockets(true);
|
||||
MachineStuff.SendMachineMatrix();
|
||||
|
||||
@@ -340,7 +340,7 @@ namespace MouseWithoutBorders.Class
|
||||
public void Reconnect()
|
||||
{
|
||||
SocketStuff.InvalidKeyFound = false;
|
||||
InitAndCleanup.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSockets(true);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
@@ -397,7 +397,7 @@ namespace MouseWithoutBorders.Class
|
||||
using var asyncFlowControl = ExecutionContext.SuppressFlow();
|
||||
|
||||
Common.InputCallbackThreadID = Thread.CurrentThread.ManagedThreadId;
|
||||
while (!InitAndCleanup.InitDone)
|
||||
while (!Common.InitDone)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace MouseWithoutBorders.Class
|
||||
if (shouldReopenSockets)
|
||||
{
|
||||
SocketStuff.InvalidKeyFound = false;
|
||||
InitAndCleanup.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSockets(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ using MouseWithoutBorders.Core;
|
||||
// </history>
|
||||
using MouseWithoutBorders.Exceptions;
|
||||
|
||||
using Clipboard = MouseWithoutBorders.Core.Clipboard;
|
||||
using Thread = MouseWithoutBorders.Core.Thread;
|
||||
|
||||
[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Byte[])", Justification = "Dotnet port with style preservation")]
|
||||
@@ -282,7 +281,7 @@ namespace MouseWithoutBorders.Class
|
||||
* */
|
||||
|
||||
Common.GetMachineName(); // IPs might have been changed
|
||||
InitAndCleanup.UpdateMachineTimeAndID();
|
||||
Common.UpdateMachineTimeAndID();
|
||||
|
||||
Logger.LogDebug("Creating sockets...");
|
||||
|
||||
@@ -309,7 +308,7 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
Logger.TelemetryLogTrace("Restarting the service dues to WSAEADDRINUSE.", SeverityLevel.Warning);
|
||||
Program.StartService();
|
||||
InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET;
|
||||
Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1249,7 +1248,7 @@ namespace MouseWithoutBorders.Class
|
||||
// WSAECONNRESET
|
||||
if (e is ExpectedSocketException se && se.ShouldReconnect)
|
||||
{
|
||||
InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET;
|
||||
Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
|
||||
Logger.Log($"MainTCPRoutine: {nameof(FlagReopenSocketIfNeeded)}");
|
||||
}
|
||||
}
|
||||
@@ -1307,7 +1306,7 @@ namespace MouseWithoutBorders.Class
|
||||
}
|
||||
catch (ObjectDisposedException e)
|
||||
{
|
||||
InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET;
|
||||
Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
|
||||
UpdateTcpSockets(currentTcp, SocketStatus.ForceClosed);
|
||||
currentSocket.Close();
|
||||
Logger.Log($"{nameof(MainTCPRoutine)}: The socket could have been closed/disposed by other threads: {e.Message}");
|
||||
@@ -1354,10 +1353,10 @@ namespace MouseWithoutBorders.Class
|
||||
* In this case, we should give ONE try to reconnect.
|
||||
*/
|
||||
|
||||
if (InitAndCleanup.ReopenSocketDueToReadError)
|
||||
if (Common.ReopenSocketDueToReadError)
|
||||
{
|
||||
InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_WSAECONNRESET;
|
||||
InitAndCleanup.ReopenSocketDueToReadError = false;
|
||||
Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
|
||||
Common.ReopenSocketDueToReadError = false;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1642,7 +1641,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
bool clientPushData = true;
|
||||
ClipboardPostAction postAction = ClipboardPostAction.Other;
|
||||
bool handShaken = Clipboard.ShakeHand(ref remoteEndPoint, s, out Stream enStream, out Stream deStream, ref clientPushData, ref postAction);
|
||||
bool handShaken = Common.ShakeHand(ref remoteEndPoint, s, out Stream enStream, out Stream deStream, ref clientPushData, ref postAction);
|
||||
|
||||
if (!handShaken)
|
||||
{
|
||||
@@ -1657,7 +1656,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
if (clientPushData)
|
||||
{
|
||||
Clipboard.ReceiveAndProcessClipboardData(remoteEndPoint, s, enStream, deStream, $"{postAction}");
|
||||
Common.ReceiveAndProcessClipboardData(remoteEndPoint, s, enStream, deStream, $"{postAction}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1681,23 +1680,23 @@ namespace MouseWithoutBorders.Class
|
||||
const int CLOSE_TIMEOUT = 10;
|
||||
byte[] header = new byte[1024];
|
||||
string headerString = string.Empty;
|
||||
if (Clipboard.LastDragDropFile != null)
|
||||
if (Common.LastDragDropFile != null)
|
||||
{
|
||||
string fileName = null;
|
||||
|
||||
if (!Launch.ImpersonateLoggedOnUserAndDoSomething(() =>
|
||||
{
|
||||
if (!File.Exists(Clipboard.LastDragDropFile))
|
||||
if (!File.Exists(Common.LastDragDropFile))
|
||||
{
|
||||
headerString = Directory.Exists(Clipboard.LastDragDropFile)
|
||||
? $"{0}*{Clipboard.LastDragDropFile} - Folder is not supported, zip it first!"
|
||||
: Clipboard.LastDragDropFile.Contains("- File too big")
|
||||
? $"{0}*{Clipboard.LastDragDropFile}"
|
||||
: $"{0}*{Clipboard.LastDragDropFile} not found!";
|
||||
headerString = Directory.Exists(Common.LastDragDropFile)
|
||||
? $"{0}*{Common.LastDragDropFile} - Folder is not supported, zip it first!"
|
||||
: Common.LastDragDropFile.Contains("- File too big")
|
||||
? $"{0}*{Common.LastDragDropFile}"
|
||||
: $"{0}*{Common.LastDragDropFile} not found!";
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = Clipboard.LastDragDropFile;
|
||||
fileName = Common.LastDragDropFile;
|
||||
headerString = $"{new FileInfo(fileName).Length}*{fileName}";
|
||||
}
|
||||
}))
|
||||
@@ -1740,11 +1739,11 @@ namespace MouseWithoutBorders.Class
|
||||
Logger.Log(log);
|
||||
}
|
||||
}
|
||||
else if (!Clipboard.IsClipboardDataImage && Clipboard.LastClipboardData != null)
|
||||
else if (!Common.IsClipboardDataImage && Common.LastClipboardData != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] data = Clipboard.LastClipboardData;
|
||||
byte[] data = Common.LastClipboardData;
|
||||
|
||||
headerString = $"{data.Length}*{"text"}";
|
||||
Common.GetBytesU(headerString).CopyTo(header, 0);
|
||||
@@ -1774,9 +1773,9 @@ namespace MouseWithoutBorders.Class
|
||||
Logger.Log(log);
|
||||
}
|
||||
}
|
||||
else if (Clipboard.LastClipboardData != null && Clipboard.LastClipboardData.Length > 0)
|
||||
else if (Common.LastClipboardData != null && Common.LastClipboardData.Length > 0)
|
||||
{
|
||||
byte[] data = Clipboard.LastClipboardData;
|
||||
byte[] data = Common.LastClipboardData;
|
||||
|
||||
headerString = $"{data.Length}*{"image"}";
|
||||
Common.GetBytesU(headerString).CopyTo(header, 0);
|
||||
@@ -1985,8 +1984,8 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
tcp = null;
|
||||
Setting.Values.MachineId = Common.Ran.Next();
|
||||
InitAndCleanup.UpdateMachineTimeAndID();
|
||||
InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_HOTKEY;
|
||||
Common.UpdateMachineTimeAndID();
|
||||
Common.PleaseReopenSocket = Common.REOPEN_WHEN_HOTKEY;
|
||||
|
||||
Logger.TelemetryLogTrace("MachineID conflict.", SeverityLevel.Information);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ internal static class DragDrop
|
||||
if (wParam == Common.WM_RBUTTONUP && IsDropping)
|
||||
{
|
||||
IsDropping = false;
|
||||
Clipboard.LastIDWithClipboardData = ID.NONE;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ internal static class DragDrop
|
||||
{
|
||||
if (!string.IsNullOrEmpty(dragFileName) && (File.Exists(dragFileName) || Directory.Exists(dragFileName)))
|
||||
{
|
||||
Clipboard.LastDragDropFile = dragFileName;
|
||||
Common.LastDragDropFile = dragFileName;
|
||||
/*
|
||||
* possibleDropMachineID is used as desID sent in DragDropStep06();
|
||||
* */
|
||||
@@ -270,7 +270,7 @@ internal static class DragDrop
|
||||
else
|
||||
{
|
||||
IsDragging = false;
|
||||
Clipboard.LastIDWithClipboardData = ID.NONE;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,7 +280,7 @@ internal static class DragDrop
|
||||
Logger.LogDebug("DragDropStep10: Hide the form and get data...");
|
||||
IsDropping = false;
|
||||
IsDragging = false;
|
||||
Clipboard.LastIDWithClipboardData = ID.NONE;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
@@ -288,7 +288,7 @@ internal static class DragDrop
|
||||
});
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersDragAndDropEvent());
|
||||
Clipboard.GetRemoteClipboard("desktop");
|
||||
Common.GetRemoteClipboard("desktop");
|
||||
}
|
||||
|
||||
internal static void DragDropStep11()
|
||||
@@ -298,8 +298,8 @@ internal static class DragDrop
|
||||
IsDropping = false;
|
||||
IsDragging = false;
|
||||
DragMachine = (ID)1;
|
||||
Clipboard.LastIDWithClipboardData = ID.NONE;
|
||||
Clipboard.LastDragDropFile = null;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
Common.LastDragDropFile = null;
|
||||
MouseDown = false;
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ internal static class DragDrop
|
||||
{
|
||||
Logger.LogDebug("DragDropStep12: ClipboardDragDropEnd received");
|
||||
IsDropping = false;
|
||||
Clipboard.LastIDWithClipboardData = ID.NONE;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
|
||||
@@ -78,7 +78,7 @@ internal static class Event
|
||||
// if they are, check that there is no application running in fullscreen mode before switching.
|
||||
if (!p.IsEmpty && Common.IsEasyMouseSwitchAllowed())
|
||||
{
|
||||
Clipboard.HasSwitchedMachineSinceLastCopy = true;
|
||||
Common.HasSwitchedMachineSinceLastCopy = true;
|
||||
|
||||
Logger.LogDebug(string.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
@@ -218,10 +218,10 @@ internal static class Event
|
||||
|
||||
if (MachineStuff.desMachineID == Common.MachineID)
|
||||
{
|
||||
if (Common.GetTick() - Clipboard.clipboardCopiedTime < Clipboard.BIG_CLIPBOARD_DATA_TIMEOUT)
|
||||
if (Common.GetTick() - Common.clipboardCopiedTime < Common.BIG_CLIPBOARD_DATA_TIMEOUT)
|
||||
{
|
||||
Clipboard.clipboardCopiedTime = 0;
|
||||
Clipboard.GetRemoteClipboard("PrepareToSwitchToMachine");
|
||||
Common.clipboardCopiedTime = 0;
|
||||
Common.GetRemoteClipboard("PrepareToSwitchToMachine");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -119,7 +119,7 @@ internal static class Helper
|
||||
|
||||
if (MachineStuff.NewDesMachineID == Common.MachineID)
|
||||
{
|
||||
InitAndCleanup.ReleaseAllKeys();
|
||||
Common.ReleaseAllKeys();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,7 +317,7 @@ internal static class Helper
|
||||
Common.GetInputDesktop(),
|
||||
0);
|
||||
|
||||
Clipboard.HasSwitchedMachineSinceLastCopy = true;
|
||||
Common.HasSwitchedMachineSinceLastCopy = true;
|
||||
|
||||
// Common.CreateLowIntegrityProcess("\"" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBordersHelper.exe\"", string.Empty, 0, false, 0);
|
||||
var processes = Process.GetProcessesByName(HelperProcessName);
|
||||
|
||||
@@ -1,278 +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.Globalization;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
|
||||
using Microsoft.Win32;
|
||||
using MouseWithoutBorders.Class;
|
||||
using Windows.UI.Input.Preview.Injection;
|
||||
|
||||
// <summary>
|
||||
// Initialization and clean up.
|
||||
// </summary>
|
||||
// <history>
|
||||
// 2008 created by Truong Do (ductdo).
|
||||
// 2009-... modified by Truong Do (TruongDo).
|
||||
// 2023- Included in PowerToys.
|
||||
// </history>
|
||||
namespace MouseWithoutBorders.Core;
|
||||
|
||||
internal static class InitAndCleanup
|
||||
{
|
||||
private static bool initDone;
|
||||
internal static int REOPEN_WHEN_WSAECONNRESET = -10054;
|
||||
internal static int REOPEN_WHEN_HOTKEY = -10055;
|
||||
internal static int PleaseReopenSocket;
|
||||
internal static bool ReopenSocketDueToReadError;
|
||||
|
||||
private static DateTime LastResumeSuspendTime { get; set; } = DateTime.UtcNow;
|
||||
|
||||
internal static bool InitDone
|
||||
{
|
||||
get => InitAndCleanup.initDone;
|
||||
set => InitAndCleanup.initDone = value;
|
||||
}
|
||||
|
||||
internal static void UpdateMachineTimeAndID()
|
||||
{
|
||||
Common.MachineName = Common.MachineName.Trim();
|
||||
_ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
|
||||
}
|
||||
|
||||
private static void InitializeMachinePoolFromSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
MachineInf[] info = MachinePoolHelpers.LoadMachineInfoFromMachinePoolStringSetting(Setting.Values.MachinePoolString);
|
||||
for (int i = 0; i < info.Length; i++)
|
||||
{
|
||||
info[i].Name = info[i].Name.Trim();
|
||||
}
|
||||
|
||||
MachineStuff.MachinePool.Initialize(info);
|
||||
MachineStuff.MachinePool.ResetIPAddressesForDeadMachines(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log(ex);
|
||||
MachineStuff.MachinePool.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetupMachineNameAndID()
|
||||
{
|
||||
try
|
||||
{
|
||||
Common.GetMachineName();
|
||||
Common.DesMachineID = MachineStuff.NewDesMachineID = Common.MachineID;
|
||||
|
||||
// MessageBox.Show(machineID.ToString(CultureInfo.CurrentCulture)); // For test
|
||||
InitializeMachinePoolFromSettings();
|
||||
|
||||
Common.MachineName = Common.MachineName.Trim();
|
||||
_ = MachineStuff.MachinePool.LearnMachine(Common.MachineName);
|
||||
_ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
|
||||
|
||||
MachineStuff.UpdateMachinePoolStringSetting();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
_ = Helper.GetUserName();
|
||||
Common.GeneratedKey = true;
|
||||
|
||||
try
|
||||
{
|
||||
Common.MyKey = Setting.Values.MyKey;
|
||||
int tmp = Setting.Values.MyKeyDaysToExpire;
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
Common.KeyCorrupted = true;
|
||||
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
|
||||
Logger.Log(e.Message);
|
||||
}
|
||||
catch (CryptographicException e)
|
||||
{
|
||||
Common.KeyCorrupted = true;
|
||||
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
|
||||
Logger.Log(e.Message);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
InputSimulation.Injector = InputInjector.TryCreate();
|
||||
if (InputSimulation.Injector != null)
|
||||
{
|
||||
InputSimulation.MoveMouseRelative(0, 0);
|
||||
NativeMethods.InjectMouseInputAvailable = true;
|
||||
}
|
||||
}
|
||||
catch (EntryPointNotFoundException)
|
||||
{
|
||||
NativeMethods.InjectMouseInputAvailable = false;
|
||||
Logger.Log($"{nameof(NativeMethods.InjectMouseInputAvailable)} = false");
|
||||
}
|
||||
|
||||
bool dummy = Setting.Values.DrawMouseEx;
|
||||
Common.Is64bitOS = IntPtr.Size == 8;
|
||||
Common.tcpPort = Setting.Values.TcpPort;
|
||||
Common.GetScreenConfig();
|
||||
Common.PackageSent = new PackageMonitor(0);
|
||||
Common.PackageReceived = new PackageMonitor(0);
|
||||
SetupMachineNameAndID();
|
||||
Common.InitEncryption();
|
||||
CreateHelperThreads();
|
||||
|
||||
SystemEvents.DisplaySettingsChanged += new EventHandler(Common.SystemEvents_DisplaySettingsChanged);
|
||||
NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
|
||||
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
|
||||
PleaseReopenSocket = 9;
|
||||
/* TODO: Telemetry for the matrix? */
|
||||
}
|
||||
|
||||
private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
|
||||
{
|
||||
Helper.WndProcCounter++;
|
||||
|
||||
if (e.Mode is PowerModes.Resume or PowerModes.Suspend)
|
||||
{
|
||||
Logger.TelemetryLogTrace($"{nameof(SystemEvents_PowerModeChanged)}: {e.Mode}", SeverityLevel.Information);
|
||||
LastResumeSuspendTime = DateTime.UtcNow;
|
||||
MachineStuff.SwitchToMultipleMode(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateHelperThreads()
|
||||
{
|
||||
// NOTE(@yuyoyuppe): service crashes while trying to obtain this info, disabling.
|
||||
/*
|
||||
Thread watchDogThread = new(new ThreadStart(WatchDogThread), nameof(WatchDogThread));
|
||||
watchDogThread.Priority = ThreadPriority.Highest;
|
||||
watchDogThread.Start();
|
||||
*/
|
||||
|
||||
Common.helper = new Thread(new ThreadStart(Helper.HelperThread), "Helper Thread");
|
||||
Common.helper.SetApartmentState(ApartmentState.STA);
|
||||
Common.helper.Start();
|
||||
}
|
||||
|
||||
private static void AskHelperThreadsToExit(int waitTime)
|
||||
{
|
||||
Helper.signalHelperToExit = true;
|
||||
Helper.signalWatchDogToExit = true;
|
||||
_ = Common.EvSwitch.Set();
|
||||
|
||||
int c = 0;
|
||||
if (Common.helper != null && c < waitTime)
|
||||
{
|
||||
while (Helper.signalHelperToExit)
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
||||
Common.helper = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Cleanup()
|
||||
{
|
||||
try
|
||||
{
|
||||
Common.SendByeBye();
|
||||
|
||||
// UnhookClipboard();
|
||||
AskHelperThreadsToExit(500);
|
||||
Common.MainForm.NotifyIcon.Visible = false;
|
||||
Common.MainForm.NotifyIcon.Dispose();
|
||||
Common.CloseAllFormsAndHooks();
|
||||
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
Common.Sk?.Close(true);
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static long lastReleaseAllKeysCall;
|
||||
|
||||
internal static void ReleaseAllKeys()
|
||||
{
|
||||
if (Math.Abs(Common.GetTick() - lastReleaseAllKeysCall) < 2000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lastReleaseAllKeysCall = Common.GetTick();
|
||||
|
||||
KEYBDDATA kd;
|
||||
kd.dwFlags = (int)Common.LLKHF.UP;
|
||||
|
||||
VK[] keys = new VK[]
|
||||
{
|
||||
VK.LSHIFT, VK.LCONTROL, VK.LMENU, VK.LWIN, VK.RSHIFT,
|
||||
VK.RCONTROL, VK.RMENU, VK.RWIN, VK.SHIFT, VK.MENU, VK.CONTROL,
|
||||
};
|
||||
|
||||
Logger.LogDebug("***** ReleaseAllKeys has been called! *****:");
|
||||
|
||||
foreach (VK vk in keys)
|
||||
{
|
||||
if ((NativeMethods.GetAsyncKeyState((IntPtr)vk) & 0x8000) != 0)
|
||||
{
|
||||
Logger.LogDebug(vk.ToString() + " is down, release it...");
|
||||
Common.Hook?.ResetLastSwitchKeys(); // Sticky key can turn ALL PC mode on (CtrlCtrlCtrl)
|
||||
kd.wVk = (int)vk;
|
||||
InputSimulation.SendKey(kd);
|
||||
Common.Hook?.ResetLastSwitchKeys();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
|
||||
{
|
||||
Logger.LogDebug("NetworkAvailabilityEventArgs.IsAvailable: " + e.IsAvailable.ToString(CultureInfo.InvariantCulture));
|
||||
Helper.WndProcCounter++;
|
||||
ScheduleReopenSocketsDueToNetworkChanges(!e.IsAvailable);
|
||||
}
|
||||
|
||||
private static void ScheduleReopenSocketsDueToNetworkChanges(bool closeSockets = true)
|
||||
{
|
||||
if (closeSockets)
|
||||
{
|
||||
// Slept/hibernated machine may still have the sockets' status as Connected:( (unchanged) so it would not re-connect after a timeout when waking up.
|
||||
// Closing the sockets when it is going to sleep/hibernate will trigger the reconnection faster when it wakes up.
|
||||
Common.DoSomethingInUIThread(
|
||||
() =>
|
||||
{
|
||||
SocketStuff s = Common.Sk;
|
||||
Common.Sk = null;
|
||||
s?.Close(false);
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
if (!Common.IsMyDesktopActive())
|
||||
{
|
||||
PleaseReopenSocket = 0;
|
||||
}
|
||||
else if (PleaseReopenSocket != 10)
|
||||
{
|
||||
PleaseReopenSocket = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,24 +247,22 @@ internal static class Logger
|
||||
|
||||
internal static void DumpStaticTypes(StringBuilder sb, int level)
|
||||
{
|
||||
var staticTypes = new List<Type>
|
||||
{
|
||||
typeof(Clipboard),
|
||||
typeof(DragDrop),
|
||||
typeof(Event),
|
||||
typeof(InitAndCleanup),
|
||||
typeof(Helper),
|
||||
typeof(Launch),
|
||||
typeof(Logger),
|
||||
typeof(MachineStuff),
|
||||
typeof(Receiver),
|
||||
typeof(Service),
|
||||
};
|
||||
foreach (var staticType in staticTypes)
|
||||
{
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $"[{staticType.Name}]\r\n===============");
|
||||
Logger.DumpType(sb, staticType, 0, level);
|
||||
}
|
||||
sb.AppendLine($"[{nameof(DragDrop)}]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(DragDrop), 0, level);
|
||||
sb.AppendLine($"[{nameof(Event)}]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Event), 0, level);
|
||||
sb.AppendLine($"[{nameof(Helper)}]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Helper), 0, level);
|
||||
sb.AppendLine($"[{nameof(Launch)}]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Launch), 0, level);
|
||||
sb.AppendLine($"[{nameof(Logger)}]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Logger), 0, level);
|
||||
sb.AppendLine($"[{nameof(MachineStuff)}]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(MachineStuff), 0, level);
|
||||
sb.AppendLine($"[{nameof(Receiver)}]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Receiver), 0, level);
|
||||
sb.AppendLine($"[{nameof(Service)}]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Service), 0, level);
|
||||
}
|
||||
|
||||
internal static bool PrivateDump(StringBuilder sb, object obj, string objName, int level, int maxLevel, bool stop)
|
||||
|
||||
@@ -992,7 +992,7 @@ internal static class MachineStuff
|
||||
Setting.Values.MatrixOneRow = !((package.Type & PackageType.MatrixTwoRowFlag) == PackageType.MatrixTwoRowFlag);
|
||||
MachineMatrix = MachineMatrix; // Save
|
||||
|
||||
InitAndCleanup.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSocketDueToReadError = true;
|
||||
|
||||
UpdateClientSockets("UpdateMachineMatrix");
|
||||
|
||||
@@ -1044,7 +1044,7 @@ internal static class MachineStuff
|
||||
Common.MoveMouseToCenter();
|
||||
}
|
||||
|
||||
InitAndCleanup.ReleaseAllKeys();
|
||||
Common.ReleaseAllKeys();
|
||||
|
||||
Common.UpdateMultipleModeIconAndMenu();
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ internal static class Receiver
|
||||
|
||||
if (!p.IsEmpty)
|
||||
{
|
||||
Clipboard.HasSwitchedMachineSinceLastCopy = true;
|
||||
Common.HasSwitchedMachineSinceLastCopy = true;
|
||||
|
||||
Logger.LogDebug(string.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
@@ -274,7 +274,7 @@ internal static class Receiver
|
||||
Common.PackageReceived.Clipboard++;
|
||||
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
|
||||
{
|
||||
Clipboard.clipboardCopiedTime = Common.GetTick();
|
||||
Common.clipboardCopiedTime = Common.GetTick();
|
||||
GetNameOfMachineWithClipboardData(package);
|
||||
SignalBigClipboardData();
|
||||
}
|
||||
@@ -282,10 +282,10 @@ internal static class Receiver
|
||||
break;
|
||||
|
||||
case PackageType.MachineSwitched:
|
||||
if (Common.GetTick() - Clipboard.clipboardCopiedTime < Clipboard.BIG_CLIPBOARD_DATA_TIMEOUT && (package.Des == Common.MachineID))
|
||||
if (Common.GetTick() - Common.clipboardCopiedTime < Common.BIG_CLIPBOARD_DATA_TIMEOUT && (package.Des == Common.MachineID))
|
||||
{
|
||||
Clipboard.clipboardCopiedTime = 0;
|
||||
Clipboard.GetRemoteClipboard("PackageType.MachineSwitched");
|
||||
Common.clipboardCopiedTime = 0;
|
||||
Common.GetRemoteClipboard("PackageType.MachineSwitched");
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -297,7 +297,7 @@ internal static class Receiver
|
||||
if (package.Des == Common.MachineID || package.Des == ID.ALL)
|
||||
{
|
||||
GetNameOfMachineWithClipboardData(package);
|
||||
Clipboard.GetRemoteClipboard("mspaint," + Clipboard.LastMachineWithClipboardData);
|
||||
Common.GetRemoteClipboard("mspaint," + Common.LastMachineWithClipboardData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,10 +326,10 @@ internal static class Receiver
|
||||
Thread.UpdateThreads(thread);
|
||||
|
||||
string remoteMachine = package.MachineName;
|
||||
System.Net.Sockets.TcpClient client = Clipboard.ConnectToRemoteClipboardSocket(remoteMachine);
|
||||
System.Net.Sockets.TcpClient client = Common.ConnectToRemoteClipboardSocket(remoteMachine);
|
||||
bool clientPushData = true;
|
||||
|
||||
if (Clipboard.ShakeHand(ref remoteMachine, client.Client, out Stream enStream, out Stream deStream, ref clientPushData, ref package.PostAction))
|
||||
if (Common.ShakeHand(ref remoteMachine, client.Client, out Stream enStream, out Stream deStream, ref clientPushData, ref package.PostAction))
|
||||
{
|
||||
SocketStuff.SendClipboardData(client.Client, enStream);
|
||||
}
|
||||
@@ -360,7 +360,7 @@ internal static class Receiver
|
||||
|
||||
case PackageType.ClipboardText:
|
||||
case PackageType.ClipboardImage:
|
||||
Clipboard.clipboardCopiedTime = 0;
|
||||
Common.clipboardCopiedTime = 0;
|
||||
if (package.Type == PackageType.ClipboardImage)
|
||||
{
|
||||
Common.PackageReceived.ClipboardImage++;
|
||||
@@ -372,7 +372,7 @@ internal static class Receiver
|
||||
|
||||
if (tcp != null)
|
||||
{
|
||||
Clipboard.ReceiveClipboardDataUsingTCP(
|
||||
Common.ReceiveClipboardDataUsingTCP(
|
||||
package,
|
||||
package.Type == PackageType.ClipboardImage,
|
||||
tcp);
|
||||
@@ -381,10 +381,10 @@ internal static class Receiver
|
||||
break;
|
||||
|
||||
case PackageType.HideMouse:
|
||||
Clipboard.HasSwitchedMachineSinceLastCopy = true;
|
||||
Common.HasSwitchedMachineSinceLastCopy = true;
|
||||
Common.HideMouseCursor(true);
|
||||
Helper.MainFormDotEx(false);
|
||||
InitAndCleanup.ReleaseAllKeys();
|
||||
Common.ReleaseAllKeys();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -405,11 +405,11 @@ internal static class Receiver
|
||||
|
||||
internal static void GetNameOfMachineWithClipboardData(DATA package)
|
||||
{
|
||||
Clipboard.LastIDWithClipboardData = package.Src;
|
||||
List<MachineInf> matchingMachines = MachineStuff.MachinePool.TryFindMachineByID(Clipboard.LastIDWithClipboardData);
|
||||
Common.LastIDWithClipboardData = package.Src;
|
||||
List<MachineInf> matchingMachines = MachineStuff.MachinePool.TryFindMachineByID(Common.LastIDWithClipboardData);
|
||||
if (matchingMachines.Count >= 1)
|
||||
{
|
||||
Clipboard.LastMachineWithClipboardData = matchingMachines[0].Name.Trim();
|
||||
Common.LastMachineWithClipboardData = matchingMachines[0].Name.Trim();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace MouseWithoutBorders
|
||||
if ((connectedClientSocket = Common.GetConnectedClientSocket()) != null)
|
||||
{
|
||||
ShowStatus($"Connected from local IP Address: {connectedClientSocket.Address}.");
|
||||
InitAndCleanup.UpdateMachineTimeAndID();
|
||||
Common.UpdateMachineTimeAndID();
|
||||
|
||||
Common.MMSleep(1);
|
||||
connected = true;
|
||||
|
||||
@@ -22,8 +22,6 @@ using Microsoft.PowerToys.Telemetry;
|
||||
// </history>
|
||||
using MouseWithoutBorders.Class;
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
using Clipboard = MouseWithoutBorders.Core.Clipboard;
|
||||
using Timer = System.Windows.Forms.Timer;
|
||||
|
||||
[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#buttonOK_Click(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
|
||||
@@ -112,7 +110,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
SocketStuff.InvalidKeyFound = false;
|
||||
showInvalidKeyMessage = false;
|
||||
InitAndCleanup.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSockets(true);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
@@ -782,7 +780,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
ShowUpdateMessage();
|
||||
|
||||
Clipboard.HasSwitchedMachineSinceLastCopy = true;
|
||||
Common.HasSwitchedMachineSinceLastCopy = true;
|
||||
}
|
||||
|
||||
private void CheckBoxDisableCAD_CheckedChanged(object sender, EventArgs e)
|
||||
|
||||
@@ -139,13 +139,13 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
if (cleanup)
|
||||
{
|
||||
InitAndCleanup.Cleanup();
|
||||
Common.Cleanup();
|
||||
}
|
||||
|
||||
Helper.WndProcCounter++;
|
||||
if (!Common.RunOnScrSaverDesktop)
|
||||
{
|
||||
InitAndCleanup.ReleaseAllKeys();
|
||||
Common.ReleaseAllKeys();
|
||||
}
|
||||
|
||||
Helper.RunDDHelper(true);
|
||||
@@ -412,7 +412,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
count = 0;
|
||||
|
||||
InitAndCleanup.InitDone = true;
|
||||
Common.InitDone = true;
|
||||
#if SHOW_ON_WINLOGON
|
||||
if (Common.RunOnLogonDesktop)
|
||||
{
|
||||
@@ -423,39 +423,39 @@ namespace MouseWithoutBorders
|
||||
|
||||
if ((count % 2) == 0)
|
||||
{
|
||||
if (InitAndCleanup.PleaseReopenSocket == 10 || (InitAndCleanup.PleaseReopenSocket > 0 && count > 0 && count % 300 == 0))
|
||||
if (Common.PleaseReopenSocket == 10 || (Common.PleaseReopenSocket > 0 && count > 0 && count % 300 == 0))
|
||||
{
|
||||
if (!Common.AtLeastOneSocketEstablished() || InitAndCleanup.PleaseReopenSocket == 10)
|
||||
if (!Common.AtLeastOneSocketEstablished() || Common.PleaseReopenSocket == 10)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
if (InitAndCleanup.PleaseReopenSocket > 0)
|
||||
if (Common.PleaseReopenSocket > 0)
|
||||
{
|
||||
InitAndCleanup.PleaseReopenSocket--;
|
||||
Common.PleaseReopenSocket--;
|
||||
}
|
||||
|
||||
// Double check.
|
||||
if (!Common.AtLeastOneSocketEstablished())
|
||||
{
|
||||
Common.GetMachineName();
|
||||
Logger.LogDebug("Common.pleaseReopenSocket: " + InitAndCleanup.PleaseReopenSocket.ToString(CultureInfo.InvariantCulture));
|
||||
Logger.LogDebug("Common.pleaseReopenSocket: " + Common.PleaseReopenSocket.ToString(CultureInfo.InvariantCulture));
|
||||
Common.ReopenSockets(false);
|
||||
MachineStuff.NewDesMachineID = Common.DesMachineID = Common.MachineID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InitAndCleanup.PleaseReopenSocket = 0;
|
||||
Common.PleaseReopenSocket = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (InitAndCleanup.PleaseReopenSocket == InitAndCleanup.REOPEN_WHEN_HOTKEY)
|
||||
if (Common.PleaseReopenSocket == Common.REOPEN_WHEN_HOTKEY)
|
||||
{
|
||||
InitAndCleanup.PleaseReopenSocket = 0;
|
||||
Common.PleaseReopenSocket = 0;
|
||||
Common.ReopenSockets(true);
|
||||
}
|
||||
else if (InitAndCleanup.PleaseReopenSocket == InitAndCleanup.REOPEN_WHEN_WSAECONNRESET)
|
||||
else if (Common.PleaseReopenSocket == Common.REOPEN_WHEN_WSAECONNRESET)
|
||||
{
|
||||
InitAndCleanup.PleaseReopenSocket = 0;
|
||||
Common.PleaseReopenSocket = 0;
|
||||
Thread.Sleep(1000);
|
||||
MachineStuff.UpdateClientSockets("REOPEN_WHEN_WSAECONNRESET");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,28 @@
|
||||
[Other Logs]
|
||||
===============
|
||||
= MouseWithoutBorders.Common
|
||||
Comma = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
Star = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
NullSeparator = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
lastClipboardEventTime = 0
|
||||
clipboardCopiedTime = 0
|
||||
<LastIDWithClipboardData>k__BackingField = NONE
|
||||
<NextClipboardViewer>k__BackingField = 0
|
||||
<IsClipboardDataImage>k__BackingField = False
|
||||
lastClipboardObject =
|
||||
<HasSwitchedMachineSinceLastCopy>k__BackingField = False
|
||||
ClipboardThreadOldLock = Lock
|
||||
--_owningThreadId = 0
|
||||
--_state = 0
|
||||
--_recursionCount = 0
|
||||
--_spinCount = 22
|
||||
--_waiterStartTimeMs = 0
|
||||
--s_contentionCount = 0
|
||||
--s_maxSpinCount = 22
|
||||
--s_minSpinCountForAdaptiveSpin = -100
|
||||
screenWidth = 0
|
||||
screenHeight = 0
|
||||
lastX = 0
|
||||
@@ -77,6 +99,17 @@ LegalKeyDictionary = Concurrent.ConcurrentDictionary`2[System.String,System.Byte
|
||||
--_budget = ????????????
|
||||
--_growLockArray = True
|
||||
--_comparerIsDefaultForClasses = False
|
||||
initDone = False
|
||||
REOPEN_WHEN_WSAECONNRESET = -10054
|
||||
REOPEN_WHEN_HOTKEY = -10055
|
||||
PleaseReopenSocket = 0
|
||||
ReopenSocketDueToReadError = False
|
||||
<LastResumeSuspendTime>k__BackingField = ????????????
|
||||
--_dateData = ????????????
|
||||
--MinValue = 01/01/0001 00:00:00
|
||||
--MaxValue = 31/12/9999 23:59:59
|
||||
--UnixEpoch = 01/01/1970 00:00:00
|
||||
lastReleaseAllKeysCall = 0
|
||||
PackageSent = MouseWithoutBorders.PackageMonitor
|
||||
--Keyboard = 0
|
||||
--Mouse = 0
|
||||
@@ -120,6 +153,12 @@ p = {X=0,Y=0}
|
||||
--y = 0
|
||||
--Empty = {X=0,Y=0}
|
||||
<IpcChannelCreated>k__BackingField = False
|
||||
BIG_CLIPBOARD_DATA_TIMEOUT = 30000
|
||||
MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1048576
|
||||
MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 104857600
|
||||
TEXT_HEADER_SIZE = 12
|
||||
DATA_SIZE = 48
|
||||
TEXT_TYPE_SEP = {4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}
|
||||
TOGGLE_ICONS_SIZE = 4
|
||||
ICON_ONE = 0
|
||||
ICON_ALL = 1
|
||||
@@ -156,36 +195,6 @@ WM_KEYDOWN = 256
|
||||
WM_KEYUP = 257
|
||||
WM_SYSKEYDOWN = 260
|
||||
WM_SYSKEYUP = 261
|
||||
[Clipboard]
|
||||
===============
|
||||
Comma = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
Star = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
NullSeparator = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
lastClipboardEventTime = 0
|
||||
clipboardCopiedTime = 0
|
||||
<LastIDWithClipboardData>k__BackingField = NONE
|
||||
<NextClipboardViewer>k__BackingField = 0
|
||||
<IsClipboardDataImage>k__BackingField = False
|
||||
lastClipboardObject =
|
||||
<HasSwitchedMachineSinceLastCopy>k__BackingField = False
|
||||
ClipboardThreadOldLock = Lock
|
||||
--_owningThreadId = 0
|
||||
--_state = 0
|
||||
--_recursionCount = 0
|
||||
--_spinCount = 22
|
||||
--_waiterStartTimeMs = 0
|
||||
--s_contentionCount = 0
|
||||
--s_maxSpinCount = 22
|
||||
--s_minSpinCountForAdaptiveSpin = -100
|
||||
BIG_CLIPBOARD_DATA_TIMEOUT = 30000
|
||||
MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1048576
|
||||
MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 104857600
|
||||
TEXT_HEADER_SIZE = 12
|
||||
DATA_SIZE = 48
|
||||
TEXT_TYPE_SEP = {4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}
|
||||
[DragDrop]
|
||||
===============
|
||||
isDragging = False
|
||||
@@ -240,19 +249,6 @@ actualLastPos = {X=0,Y=0}
|
||||
--Empty = {X=0,Y=0}
|
||||
myLastX = 0
|
||||
myLastY = 0
|
||||
[InitAndCleanup]
|
||||
===============
|
||||
initDone = False
|
||||
REOPEN_WHEN_WSAECONNRESET = -10054
|
||||
REOPEN_WHEN_HOTKEY = -10055
|
||||
PleaseReopenSocket = 0
|
||||
ReopenSocketDueToReadError = False
|
||||
<LastResumeSuspendTime>k__BackingField = ????????????
|
||||
--_dateData = ????????????
|
||||
--MinValue = 01/01/0001 00:00:00
|
||||
--MaxValue = 31/12/9999 23:59:59
|
||||
--UnixEpoch = 01/01/1970 00:00:00
|
||||
lastReleaseAllKeysCall = 0
|
||||
[Helper]
|
||||
===============
|
||||
signalHelperToExit = False
|
||||
|
||||
@@ -258,6 +258,16 @@ private:
|
||||
{
|
||||
Logger::info("AlwaysOnTop settings are empty");
|
||||
}
|
||||
|
||||
if (!m_hotkey.key)
|
||||
{
|
||||
Logger::info("AlwaysOnTop is going to use default shortcut");
|
||||
m_hotkey.win = true;
|
||||
m_hotkey.alt = false;
|
||||
m_hotkey.shift = false;
|
||||
m_hotkey.ctrl = true;
|
||||
m_hotkey.key = 'T';
|
||||
}
|
||||
}
|
||||
|
||||
bool is_process_running()
|
||||
|
||||
@@ -157,33 +157,9 @@ namespace Awake
|
||||
|
||||
pidOption.AddValidator(result =>
|
||||
{
|
||||
if (result.Tokens.Count == 0)
|
||||
if (result.Tokens.Count != 0 && !int.TryParse(result.Tokens[0].Value, out _))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string tokenValue = result.Tokens[0].Value;
|
||||
|
||||
if (!int.TryParse(tokenValue, out int parsed))
|
||||
{
|
||||
string errorMessage = $"PID value in --pid could not be parsed correctly. Check that the value is valid and falls within the boundaries of Windows PID process limits. Value used: {tokenValue}.";
|
||||
Logger.LogError(errorMessage);
|
||||
result.ErrorMessage = errorMessage;
|
||||
return;
|
||||
}
|
||||
|
||||
if (parsed <= 0)
|
||||
{
|
||||
string errorMessage = $"PID value in --pid must be a positive integer. Value used: {parsed}.";
|
||||
Logger.LogError(errorMessage);
|
||||
result.ErrorMessage = errorMessage;
|
||||
return;
|
||||
}
|
||||
|
||||
// Process existence check. (We also re-validate just before binding.)
|
||||
if (!ProcessExists(parsed))
|
||||
{
|
||||
string errorMessage = $"No running process found with an ID of {parsed}.";
|
||||
string errorMessage = $"PID value in --pid could not be parsed correctly. Check that the value is valid and falls within the boundaries of Windows PID process limits. Value used: {result.Tokens[0].Value}.";
|
||||
Logger.LogError(errorMessage);
|
||||
result.ErrorMessage = errorMessage;
|
||||
}
|
||||
@@ -240,25 +216,6 @@ namespace Awake
|
||||
Manager.CompleteExit(exitCode);
|
||||
}
|
||||
|
||||
private static bool ProcessExists(int processId)
|
||||
{
|
||||
if (processId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Throws if the Process ID is not found.
|
||||
using var p = Process.GetProcessById(processId);
|
||||
return !p.HasExited;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, uint timeLimit, int pid, string expireAt, bool useParentPid)
|
||||
{
|
||||
if (pid == 0 && !useParentPid)
|
||||
@@ -314,12 +271,6 @@ namespace Awake
|
||||
|
||||
if (pid != 0)
|
||||
{
|
||||
if (!ProcessExists(pid))
|
||||
{
|
||||
Logger.LogError($"PID {pid} does not exist or is not accessible. Exiting.");
|
||||
Exit(Resources.AWAKE_EXIT_PROCESS_BINDING_FAILURE_MESSAGE, 1);
|
||||
}
|
||||
|
||||
Logger.LogInfo($"Bound to target process while also using PowerToys settings: {pid}");
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(pid, () =>
|
||||
@@ -336,7 +287,28 @@ namespace Awake
|
||||
}
|
||||
else if (pid != 0 || useParentPid)
|
||||
{
|
||||
HandleProcessScopedKeepAwake(pid, useParentPid, displayOn);
|
||||
// Second, we snap to process-based execution. Because this is something that
|
||||
// is snapped to a running entity, we only want to enable the ability to set
|
||||
// indefinite keep-awake with the display settings that the user wants to set.
|
||||
// In this context, manual (explicit) PID takes precedence over parent PID.
|
||||
int targetPid = pid != 0 ? pid : useParentPid ? Manager.GetParentProcess()?.Id ?? 0 : 0;
|
||||
|
||||
if (targetPid != 0)
|
||||
{
|
||||
Logger.LogInfo($"Bound to target process: {targetPid}");
|
||||
|
||||
Manager.SetIndefiniteKeepAwake(displayOn, targetPid);
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(targetPid, () =>
|
||||
{
|
||||
Logger.LogInfo($"Triggered PID-based exit handler for PID {targetPid}.");
|
||||
Exit(Resources.AWAKE_EXIT_BINDING_HOOK_MESSAGE, 0);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogError("Not binding to any process.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -372,62 +344,6 @@ namespace Awake
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a process-scoped keep-awake session. The application will keep the system awake
|
||||
/// indefinitely until the target process terminates.
|
||||
/// </summary>
|
||||
/// <param name="pid">The explicit process ID to monitor.</param>
|
||||
/// <param name="useParentPid">A flag indicating whether the application should monitor its
|
||||
/// parent process.</param>
|
||||
/// <param name="displayOn">Whether to keep the display on during the session.</param>
|
||||
private static void HandleProcessScopedKeepAwake(int pid, bool useParentPid, bool displayOn)
|
||||
{
|
||||
int targetPid = 0;
|
||||
|
||||
// We prioritize a user-provided PID over the parent PID. If both are given on the
|
||||
// command line, the --pid value will be used.
|
||||
if (pid != 0)
|
||||
{
|
||||
if (pid == Environment.ProcessId)
|
||||
{
|
||||
Logger.LogError("Awake cannot bind to itself, as this would lead to an indefinite keep-awake state.");
|
||||
Exit(Resources.AWAKE_EXIT_BIND_TO_SELF_FAILURE_MESSAGE, 1);
|
||||
}
|
||||
|
||||
if (!ProcessExists(pid))
|
||||
{
|
||||
Logger.LogError($"PID {pid} does not exist or is not accessible. Exiting.");
|
||||
Exit(Resources.AWAKE_EXIT_PROCESS_BINDING_FAILURE_MESSAGE, 1);
|
||||
}
|
||||
|
||||
targetPid = pid;
|
||||
}
|
||||
else if (useParentPid)
|
||||
{
|
||||
targetPid = Manager.GetParentProcess()?.Id ?? 0;
|
||||
|
||||
if (targetPid == 0)
|
||||
{
|
||||
// The parent process could not be identified.
|
||||
Logger.LogError("Failed to identify a parent process for binding.");
|
||||
Exit(Resources.AWAKE_EXIT_PARENT_BINDING_FAILURE_MESSAGE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// We have a valid non-zero PID to monitor.
|
||||
Logger.LogInfo($"Bound to target process: {targetPid}");
|
||||
|
||||
// Sets the keep-awake plan and updates the tray icon.
|
||||
Manager.SetIndefiniteKeepAwake(displayOn, targetPid);
|
||||
|
||||
// Synchronize with the target process, and trigger Exit() when it finishes.
|
||||
RunnerHelper.WaitForPowerToysRunner(targetPid, () =>
|
||||
{
|
||||
Logger.LogInfo($"Triggered PID-based exit handler for PID {targetPid}.");
|
||||
Exit(Resources.AWAKE_EXIT_BINDING_HOOK_MESSAGE, 0);
|
||||
});
|
||||
}
|
||||
|
||||
private static void AllocateLocalConsole()
|
||||
{
|
||||
Manager.AllocateConsole();
|
||||
|
||||
@@ -132,15 +132,6 @@ namespace Awake.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Exiting because the provided process ID is Awake's own..
|
||||
/// </summary>
|
||||
internal static string AWAKE_EXIT_BIND_TO_SELF_FAILURE_MESSAGE {
|
||||
get {
|
||||
return ResourceManager.GetString("AWAKE_EXIT_BIND_TO_SELF_FAILURE_MESSAGE", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Terminating from process binding hook..
|
||||
/// </summary>
|
||||
@@ -159,24 +150,6 @@ namespace Awake.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Exiting because the parent process ID could not be found..
|
||||
/// </summary>
|
||||
internal static string AWAKE_EXIT_PARENT_BINDING_FAILURE_MESSAGE {
|
||||
get {
|
||||
return ResourceManager.GetString("AWAKE_EXIT_PARENT_BINDING_FAILURE_MESSAGE", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Exiting because the requested process ID could not be found..
|
||||
/// </summary>
|
||||
internal static string AWAKE_EXIT_PROCESS_BINDING_FAILURE_MESSAGE {
|
||||
get {
|
||||
return ResourceManager.GetString("AWAKE_EXIT_PROCESS_BINDING_FAILURE_MESSAGE", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Received a signal to end the process. Making sure we quit....
|
||||
/// </summary>
|
||||
|
||||
@@ -226,13 +226,4 @@
|
||||
<data name="AWAKE_SCREEN_OFF" xml:space="preserve">
|
||||
<value>Off</value>
|
||||
</data>
|
||||
<data name="AWAKE_EXIT_PARENT_BINDING_FAILURE_MESSAGE" xml:space="preserve">
|
||||
<value>Exiting because the parent process ID could not be found.</value>
|
||||
</data>
|
||||
<data name="AWAKE_EXIT_PROCESS_BINDING_FAILURE_MESSAGE" xml:space="preserve">
|
||||
<value>Exiting because the requested process ID could not be found.</value>
|
||||
</data>
|
||||
<data name="AWAKE_EXIT_BIND_TO_SELF_FAILURE_MESSAGE" xml:space="preserve">
|
||||
<value>Exiting because the provided process ID is Awake's own.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,62 +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;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common;
|
||||
|
||||
public static class CoreLogger
|
||||
{
|
||||
public static void InitializeLogger(ILogger implementation)
|
||||
{
|
||||
_logger = implementation;
|
||||
}
|
||||
|
||||
private static ILogger? _logger;
|
||||
|
||||
public static void LogError(string message, Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
_logger?.LogError(message, ex, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
public static void LogError(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
_logger?.LogError(message, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
public static void LogWarning(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
_logger?.LogWarning(message, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
public static void LogInfo(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
_logger?.LogInfo(message, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
public static void LogDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
_logger?.LogDebug(message, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
public static void LogTrace([System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
_logger?.LogTrace(memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
void LogError(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
|
||||
|
||||
void LogError(string message, Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
|
||||
|
||||
void LogWarning(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
|
||||
|
||||
void LogInfo(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
|
||||
|
||||
void LogDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
|
||||
|
||||
void LogTrace([System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\CoreCommonProps.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Core.Common</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,21 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\CoreCommonProps.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Common" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.CmdPal.Core.Common\Microsoft.CmdPal.Core.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"$schema": "https://aka.ms/CsWin32.schema.json",
|
||||
"allowMarshaling": false
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ShowDetailsCommand" xml:space="preserve">
|
||||
<value>Show details</value>
|
||||
<comment>Name for the command that shows details of an item</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,33 +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 CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels.Commands;
|
||||
|
||||
public sealed partial class ShowDetailsCommand : InvokableCommand
|
||||
{
|
||||
public static string ShowDetailsCommandId { get; } = "com.microsoft.cmdpal.showDetails";
|
||||
|
||||
private static IconInfo IconInfo { get; } = new IconInfo("\uF000"); // KnowledgeArticle Icon
|
||||
|
||||
private DetailsViewModel Details { get; set; }
|
||||
|
||||
public ShowDetailsCommand(DetailsViewModel details)
|
||||
{
|
||||
Id = ShowDetailsCommandId;
|
||||
Name = Properties.Resources.ShowDetailsCommand;
|
||||
Icon = IconInfo;
|
||||
Details = details;
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
// Send the ShowDetailsMessage when the action is invoked
|
||||
WeakReferenceMessenger.Default.Send<ShowDetailsMessage>(new(Details));
|
||||
return CommandResult.KeepOpen();
|
||||
}
|
||||
}
|
||||
@@ -4,20 +4,23 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit.Properties;
|
||||
using System.IO;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Common.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
namespace Microsoft.CmdPal.Common.Commands;
|
||||
|
||||
public partial class OpenInConsoleCommand : InvokableCommand
|
||||
{
|
||||
internal static IconInfo OpenInConsoleIcon { get; } = new("\uE756"); // "CommandPrompt"
|
||||
internal static IconInfo OpenInConsoleIcon { get; } = new("\uE756");
|
||||
|
||||
private readonly string _path;
|
||||
|
||||
public OpenInConsoleCommand(string fullPath)
|
||||
{
|
||||
this._path = fullPath;
|
||||
this.Name = Resources.OpenInConsoleCommand_Name;
|
||||
this.Name = Resources.Indexer_Command_OpenPathInConsole;
|
||||
this.Icon = OpenInConsoleIcon;
|
||||
}
|
||||
|
||||
@@ -34,7 +37,7 @@ public partial class OpenInConsoleCommand : InvokableCommand
|
||||
}
|
||||
catch (Win32Exception ex)
|
||||
{
|
||||
ExtensionHost.LogMessage(new LogMessage($"Unable to open '{_path}'\n{ex.Message}\n{ex.StackTrace}") { State = MessageState.Error });
|
||||
Logger.LogError($"Unable to open '{_path}'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
// 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.Runtime.InteropServices;
|
||||
using ManagedCommon;
|
||||
using ManagedCsWin32;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit.Properties;
|
||||
using Microsoft.CmdPal.Common.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
namespace Microsoft.CmdPal.Common.Commands;
|
||||
|
||||
public partial class OpenPropertiesCommand : InvokableCommand
|
||||
{
|
||||
@@ -43,7 +46,7 @@ public partial class OpenPropertiesCommand : InvokableCommand
|
||||
public OpenPropertiesCommand(string fullPath)
|
||||
{
|
||||
this._path = fullPath;
|
||||
this.Name = Resources.OpenPropertiesCommand_Name;
|
||||
this.Name = Resources.Indexer_Command_OpenProperties;
|
||||
this.Icon = OpenPropertiesIcon;
|
||||
}
|
||||
|
||||
@@ -55,7 +58,7 @@ public partial class OpenPropertiesCommand : InvokableCommand
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExtensionHost.LogMessage(new LogMessage($"Error showing file properties '{_path}'\n{ex.Message}\n{ex.StackTrace}") { State = MessageState.Error });
|
||||
Logger.LogError("Error showing file properties: ", ex);
|
||||
}
|
||||
|
||||
return CommandResult.Dismiss();
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using ManagedCsWin32;
|
||||
using Microsoft.CmdPal.Common.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit.Properties;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common.Commands;
|
||||
namespace Microsoft.CmdPal.Common.Commands;
|
||||
|
||||
public partial class OpenWithCommand : InvokableCommand
|
||||
{
|
||||
@@ -44,7 +44,7 @@ public partial class OpenWithCommand : InvokableCommand
|
||||
public OpenWithCommand(string fullPath)
|
||||
{
|
||||
this._path = fullPath;
|
||||
this.Name = Resources.OpenWithCommand_Name;
|
||||
this.Name = Resources.Indexer_Command_OpenWith;
|
||||
this.Icon = OpenWithIcon;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common.Helpers;
|
||||
namespace Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Provides utility methods for building diagnostic and error messages.
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common;
|
||||
namespace Microsoft.CmdPal.Common;
|
||||
|
||||
public partial class ExtensionHostInstance
|
||||
{
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common.Helpers;
|
||||
namespace Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Thread-safe boolean implementation using atomic operations
|
||||
@@ -7,7 +7,7 @@ using System.Threading;
|
||||
|
||||
using Microsoft.UI.Dispatching;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common.Helpers;
|
||||
namespace Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
public static partial class NativeEventWaiter
|
||||
{
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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.Security.Principal;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
public static partial class RuntimeHelper
|
||||
{
|
||||
public static bool IsMSIX
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO: for whatever reason, when I ported this into the PT
|
||||
// codebase, this no longer compiled. We're only ever using it for
|
||||
// the hacked up settings and ignoring it anyways, so I'm leaving
|
||||
// it commented out for now.
|
||||
//
|
||||
// See also:
|
||||
// * https://github.com/microsoft/win32metadata/commit/6fee67ba73bfe1b126ce524f7de8d367f0317715
|
||||
// * https://github.com/microsoft/win32metadata/issues/1311
|
||||
// uint length = 0;
|
||||
// return PInvoke.GetCurrentPackageFullName(ref length, null) != WIN32_ERROR.APPMODEL_ERROR_NO_PACKAGE;
|
||||
#pragma warning disable IDE0025 // Use expression body for property
|
||||
return true;
|
||||
#pragma warning restore IDE0025 // Use expression body for property
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsOnWindows11
|
||||
{
|
||||
get
|
||||
{
|
||||
var version = Environment.OSVersion.Version;
|
||||
return version.Major >= 10 && version.Build >= 22000;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsCurrentProcessRunningAsAdmin()
|
||||
{
|
||||
var identity = WindowsIdentity.GetCurrent();
|
||||
return identity.Owner?.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid) ?? false;
|
||||
}
|
||||
|
||||
public static void VerifyCurrentProcessRunningAsAdmin()
|
||||
{
|
||||
if (!IsCurrentProcessRunningAsAdmin())
|
||||
{
|
||||
throw new UnauthorizedAccessException("This operation requires elevated privileges.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,14 @@ using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common.Helpers;
|
||||
namespace Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// An async gate that ensures only one operation runs at a time.
|
||||
/// If ExecuteAsync is called while already executing, it cancels the current execution
|
||||
/// and starts the operation again (superseding behavior).
|
||||
/// </summary>
|
||||
public partial class SupersedingAsyncGate : IDisposable
|
||||
public class SupersedingAsyncGate : IDisposable
|
||||
{
|
||||
private readonly Func<CancellationToken, Task> _action;
|
||||
private readonly Lock _lock = new();
|
||||
@@ -7,7 +7,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
using Windows.System;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common.Helpers;
|
||||
namespace Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Well-known key chords used in the Command Palette and extensions.
|
||||
@@ -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.
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.ClipboardHistory.Helpers;
|
||||
namespace Microsoft.CmdPal.Common.Messages;
|
||||
|
||||
internal enum PrimaryAction
|
||||
public partial record HideWindowMessage()
|
||||
{
|
||||
Default,
|
||||
Paste,
|
||||
Copy,
|
||||
}
|
||||
@@ -1,28 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Common</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- For MVVM Toolkit Partial Properties/AOT support -->
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<LangVersion>preview</LangVersion>
|
||||
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal\</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
|
||||
<ProjectPriFileName>$(RootNamespace).pri</ProjectPriFileName>
|
||||
|
||||
<!-- Disable SA1313 for Primary Constructor fields conflict https://learn.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors#primary-constructors -->
|
||||
<NoWarn>SA1313;</NoWarn>
|
||||
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<CsWinRTAotOptimizerEnabled>true</CsWinRTAotOptimizerEnabled>
|
||||
<ProjectPriFileName>Microsoft.CmdPal.Common.pri</ProjectPriFileName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@@ -33,14 +28,24 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(MSBuildThisFileDirectory)\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedCsWin32\ManagedCsWin32.csproj" />
|
||||
<ProjectReference Include="..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -8,7 +8,7 @@
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels.Properties {
|
||||
namespace Microsoft.CmdPal.Common.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Microsoft.CmdPal.Core.ViewModels.Properties {
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Resources {
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
@@ -36,10 +36,10 @@ namespace Microsoft.CmdPal.Core.ViewModels.Properties {
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.CmdPal.Core.ViewModels.Properties.Resources", typeof(Resources).Assembly);
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.CmdPal.Common.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
@@ -51,7 +51,7 @@ namespace Microsoft.CmdPal.Core.ViewModels.Properties {
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
@@ -61,11 +61,38 @@ namespace Microsoft.CmdPal.Core.ViewModels.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Show details.
|
||||
/// Looks up a localized string similar to Open path in console.
|
||||
/// </summary>
|
||||
public static string ShowDetailsCommand {
|
||||
internal static string Indexer_Command_OpenPathInConsole {
|
||||
get {
|
||||
return ResourceManager.GetString("ShowDetailsCommand", resourceCulture);
|
||||
return ResourceManager.GetString("Indexer_Command_OpenPathInConsole", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Properties.
|
||||
/// </summary>
|
||||
internal static string Indexer_Command_OpenProperties {
|
||||
get {
|
||||
return ResourceManager.GetString("Indexer_Command_OpenProperties", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Open with.
|
||||
/// </summary>
|
||||
internal static string Indexer_Command_OpenWith {
|
||||
get {
|
||||
return ResourceManager.GetString("Indexer_Command_OpenWith", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Show in folder.
|
||||
/// </summary>
|
||||
internal static string Indexer_Command_ShowInFolder {
|
||||
get {
|
||||
return ResourceManager.GetString("Indexer_Command_ShowInFolder", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Indexer_Command_OpenPathInConsole" xml:space="preserve">
|
||||
<value>Open path in console</value>
|
||||
</data>
|
||||
<data name="Indexer_Command_OpenProperties" xml:space="preserve">
|
||||
<value>Properties</value>
|
||||
</data>
|
||||
<data name="Indexer_Command_OpenWith" xml:space="preserve">
|
||||
<value>Open with</value>
|
||||
</data>
|
||||
<data name="Indexer_Command_ShowInFolder" xml:space="preserve">
|
||||
<value>Show in folder</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -6,7 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common.Services;
|
||||
namespace Microsoft.CmdPal.Common.Services;
|
||||
|
||||
public interface IExtensionService
|
||||
{
|
||||
@@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Windows.ApplicationModel;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common.Services;
|
||||
namespace Microsoft.CmdPal.Common.Services;
|
||||
|
||||
public interface IExtensionWrapper
|
||||
{
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.Common.Services;
|
||||
namespace Microsoft.CmdPal.Common.Services;
|
||||
|
||||
public interface IRunHistoryService
|
||||
{
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.CmdPal.Core.Common;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Foundation;
|
||||
@@ -60,7 +60,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
CoreLogger.LogDebug(message.Message);
|
||||
Logger.LogDebug(message.Message);
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
@@ -146,13 +146,14 @@ public partial class CommandBarViewModel : ObservableObject,
|
||||
return ContextKeybindingResult.Unhandled;
|
||||
}
|
||||
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(command.Command.Model, command.Model));
|
||||
if (command.HasMoreCommands)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(command.Command.Model, command.Model));
|
||||
return ContextKeybindingResult.KeepOpen;
|
||||
}
|
||||
else
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(command.Command.Model, command.Model));
|
||||
return ContextKeybindingResult.Hide;
|
||||
}
|
||||
}
|
||||
@@ -39,9 +39,14 @@ public partial class CommandContextItemViewModel(ICommandContextItem contextItem
|
||||
|
||||
IsCritical = contextItem.IsCritical;
|
||||
|
||||
RequestedShortcut = new(
|
||||
contextItem.RequestedShortcut.Modifiers,
|
||||
contextItem.RequestedShortcut.Vkey,
|
||||
contextItem.RequestedShortcut.ScanCode);
|
||||
// I actually don't think this will ever actually be null, because
|
||||
// KeyChord is a struct, which isn't nullable in WinRT
|
||||
if (contextItem.RequestedShortcut != null)
|
||||
{
|
||||
RequestedShortcut = new(
|
||||
contextItem.RequestedShortcut.Modifiers,
|
||||
contextItem.RequestedShortcut.Vkey,
|
||||
contextItem.RequestedShortcut.ScanCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.CmdPal.Core.Common;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
@@ -184,7 +184,14 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
MoreCommands = more
|
||||
.Select<IContextItem, IContextItemViewModel>(item =>
|
||||
{
|
||||
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
|
||||
if (item is ICommandContextItem contextItem)
|
||||
{
|
||||
return new CommandContextItemViewModel(contextItem, PageContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SeparatorViewModel();
|
||||
}
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
@@ -233,7 +240,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CoreLogger.LogError("error fast initializing CommandItemViewModel", ex);
|
||||
Logger.LogError("error fast initializing CommandItemViewModel", ex);
|
||||
Command = new(null, PageContext);
|
||||
_itemTitle = "Error";
|
||||
Subtitle = "Item failed to load";
|
||||
@@ -255,7 +262,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
catch (Exception ex)
|
||||
{
|
||||
Initialized |= InitializedState.Error;
|
||||
CoreLogger.LogError("error slow initializing CommandItemViewModel", ex);
|
||||
Logger.LogError("error slow initializing CommandItemViewModel", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -270,7 +277,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CoreLogger.LogError("error initializing CommandItemViewModel", ex);
|
||||
Logger.LogError("error initializing CommandItemViewModel", ex);
|
||||
Command = new(null, PageContext);
|
||||
_itemTitle = "Error";
|
||||
Subtitle = "Item failed to load";
|
||||
@@ -341,7 +348,14 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
var newContextMenu = more
|
||||
.Select<IContextItem, IContextItemViewModel>(item =>
|
||||
{
|
||||
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
|
||||
if (item is ICommandContextItem contextItem)
|
||||
{
|
||||
return new CommandContextItemViewModel(contextItem, PageContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SeparatorViewModel();
|
||||
}
|
||||
})
|
||||
.ToList();
|
||||
lock (MoreCommands)
|
||||