mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-05 02:39:59 +01:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ba99d14e1 | ||
|
|
bbbbf0954d | ||
|
|
f81ccdda3d | ||
|
|
ef7285fb9a | ||
|
|
e75a74565b | ||
|
|
1792849b98 | ||
|
|
c7fb1f6d17 | ||
|
|
a856263081 | ||
|
|
582d1320a3 | ||
|
|
3789da4305 | ||
|
|
a36f97adfb | ||
|
|
2cda53d3af | ||
|
|
74007ea465 | ||
|
|
c88a7dba6b | ||
|
|
66b7863d43 | ||
|
|
19b318a488 | ||
|
|
c606e3db43 | ||
|
|
f89ab74b29 | ||
|
|
4bbdec5044 | ||
|
|
56a727cf0d | ||
|
|
32f74e41ef | ||
|
|
e249bc5856 | ||
|
|
32b8a344a6 | ||
|
|
61c0c35e92 | ||
|
|
2eecaf4570 | ||
|
|
8f59247acb | ||
|
|
eb3ec26279 | ||
|
|
f07d37ce0d | ||
|
|
2e8602eb43 | ||
|
|
4277041b0e | ||
|
|
6801190180 | ||
|
|
067a9cf54d |
10
.github/pull_request_template.md
vendored
10
.github/pull_request_template.md
vendored
@@ -6,11 +6,11 @@
|
||||
|
||||
<!-- Please review the items on the PR checklist before submitting-->
|
||||
## PR Checklist
|
||||
* [] Applies to #xxx
|
||||
* [] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA
|
||||
* [] Tests added/passed
|
||||
* [] Requires documentation to be updated
|
||||
* [] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
|
||||
* [ ] Applies to #xxx
|
||||
* [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA
|
||||
* [ ] Tests added/passed
|
||||
* [ ] Requires documentation to be updated
|
||||
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
|
||||
|
||||
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
|
||||
## Detailed Description of the Pull Request / Additional comments
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0
|
||||
SET IsPipeline=1
|
||||
call msbuild ../installer/PowerToysSetup.sln /p:Configuration=Release /p:Platform=x64 || exit /b 1
|
||||
|
||||
@@ -4,3 +4,5 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Too
|
||||
call msbuild ../PowerToys.sln /p:Configuration=Release /p:Platform=x64 || exit /b 1
|
||||
call msbuild ../src/common/notifications/notifications_dll.vcxproj /p:Configuration=Release /p:Platform=x64 || exit /b 1
|
||||
call msbuild ../src/common/notifications_winrt/notifications.vcxproj /p:Configuration=Release /p:Platform=x64 || exit /b 1
|
||||
SET PTRoot=..
|
||||
call "..\installer\PowerToysSetup\publish.cmd"
|
||||
|
||||
@@ -41,6 +41,11 @@ build:
|
||||
name: 'Build Power Toys'
|
||||
command: '.pipelines\build.cmd'
|
||||
artifacts:
|
||||
- to: 'Symbols'
|
||||
include:
|
||||
- 'x64/**/*.pdb'
|
||||
exclude:
|
||||
- 'x64/Release/obj/**/*.pdb'
|
||||
- from: 'x64/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
@@ -127,20 +132,6 @@ build:
|
||||
- 'PowerToysSetup-*.msi'
|
||||
signing_options:
|
||||
sign_inline: true # This does signing a soon as this command completes
|
||||
# - !!buildcommand
|
||||
# name: 'Archive symbols to Symbol Server'
|
||||
# artifacts:
|
||||
# - to: 'x64 Symbols'
|
||||
# include:
|
||||
# - 'x64/Release/action_runner.pdb'
|
||||
# - 'x64/Release/Notifications.pdb'
|
||||
# - 'x64/Release/PowerRenameUWPUI.pdb'
|
||||
# - 'x64/Release/PowerToys.pdb'
|
||||
# - 'x64/Release/PowerToysSettings.pdb'
|
||||
# - 'x64/Release/modules/fancyzones.pdb'
|
||||
# - 'x64/Release/modules/FancyZonesEditor.pdb'
|
||||
# - 'x64/Release/modules/PowerRenameExt.pdb'
|
||||
# - 'x64/Release/modules/shortcut_guide.pdb'
|
||||
|
||||
package:
|
||||
commands:
|
||||
|
||||
74
README.md
74
README.md
@@ -14,7 +14,7 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
|
||||
### FancyZones
|
||||
|
||||
<img align="left" src="./doc/images/overview/FancyZones_small.png" />[FancyZones](/src/modules/fancyzones/) is a window manager that makes it easy to create complex window layouts and quickly position windows into those layouts.
|
||||
[<img align="left" src="./doc/images/overview/FancyZones_small.png" />](/src/modules/fancyzones/) [FancyZones](/src/modules/fancyzones/) is a window manager that makes it easy to create complex window layouts and quickly position windows into those layouts.
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
@@ -23,7 +23,7 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
|
||||
### Shortcut Guide
|
||||
|
||||
<img align="left" src="./doc/images/overview/Shortcut guide_small.png" />[Windows key shortcut guide](/src/modules/shortcut_guide) appears when a user holds the Windows key down for more than one second and shows the available shortcuts for the current state of the desktop.
|
||||
[<img align="left" src="./doc/images/overview/Shortcut guide_small.png" />](/src/modules/shortcut_guide) [Windows key shortcut guide](/src/modules/shortcut_guide) appears when a user holds the Windows key down for more than one second and shows the available shortcuts for the current state of the desktop.
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
@@ -32,66 +32,67 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
|
||||
### PowerRename
|
||||
|
||||
<img align="left" src="./doc/images/overview/PowerRename_small.PNG" />[PowerRename](/src/modules/powerrename) is a Windows Shell Extension for advanced bulk renaming using search and replace or regular expressions. PowerRename allows simple search and replace or more advanced regular expression matching. While you type in the search and replace input fields, the preview area will show what the items will be renamed to. PowerRename then calls into the Windows Explorer file operations engine to perform the rename. This has the benefit of allowing the rename operation to be undone after PowerRename exits. This code is based on [Chris Davis's SmartRename](https://github.com/chrdavis/SmartRename).
|
||||
[<img align="left" src="./doc/images/overview/PowerRename_small.PNG" />](/src/modules/powerrename) [PowerRename](/src/modules/powerrename) is a Windows Shell Extension for advanced bulk renaming using search and replace or regular expressions. PowerRename allows simple search and replace or more advanced regular expression matching. While you type in the search and replace input fields, the preview area will show what the items will be renamed to. PowerRename then calls into the Windows Explorer file operations engine to perform the rename. This has the benefit of allowing the rename operation to be undone after PowerRename exits. This code is based on [Chris Davis's SmartRename](https://github.com/chrdavis/SmartRename).
|
||||
<br>
|
||||
<br>
|
||||
|
||||
### File Explorer (Preview Panes)
|
||||
|
||||
<img align="left" src="./doc/images/overview/PowerPreview_small.PNG" />[File Explorer](/src/modules/previewpane) add-ons right now are just limited to Preview Pane additions for File Explorer. Preview Pane is an existing feature in the File Explorer. To enable it, you just click the View tab in the ribbon and then click "Preview Pane".
|
||||
[<img align="left" src="./doc/images/overview/PowerPreview_small.PNG" />](/src/modules/previewpane) [File Explorer](/src/modules/previewpane) add-ons right now are just limited to Preview Pane additions for File Explorer. Preview Pane is an existing feature in the File Explorer. To enable it, you just click the View tab in the ribbon and then click "Preview Pane".
|
||||
|
||||
PowerToys will now enable two types of files to be previewed: Markdown (.md) & SVG (.svg)
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
### Image Resizer
|
||||
|
||||
<img align="left" src="./doc/images/overview/ImageResizer_small.png" />[Image Resizer](/src/modules/imageresizer) is a Windows Shell Extension for quickly resizing images. With a simple right click from File Explorer, resize one or many images instantly. This code is based on [Brice Lambson's Image Resizer](https://github.com/bricelam/ImageResizer).
|
||||
[<img align="left" src="./doc/images/overview/ImageResizer_small.png" />](/src/modules/imageresizer) [Image Resizer](/src/modules/imageresizer) is a Windows Shell Extension for quickly resizing images. With a simple right click from File Explorer, resize one or many images instantly. This code is based on [Brice Lambson's Image Resizer](https://github.com/bricelam/ImageResizer).
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<!---
|
||||
### Keyboard Manager
|
||||
|
||||
<img align="left" src="./doc/images/overview/KBM_small.png" /> [Keyboard Manager](src/modules/keyboardmanager/) allows you to customize the keyboard to be more productive by remapping keys and creating your own keyboard shortcuts.
|
||||
[<img align="left" src="./doc/images/overview/KBM_small.png" />](src/modules/keyboardmanager/) [Keyboard Manager](src/modules/keyboardmanager/) allows you to customize the keyboard to be more productive by remapping keys and creating your own keyboard shortcuts. This PowerToy requires Windows 10 1903 (build 18362) or later.
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
-->
|
||||
|
||||
<!---
|
||||
### PowerToys Run
|
||||
|
||||
<img align="left" src="./doc/images/overview/PowerLauncher_small.png" /> [PowerToys Run](src/modules/launcher/) is a new toy in PowerToys that can help you search and launch your app instantly! It is open source and modular for additional plugins. Window Walker is now inside!
|
||||
[<img align="left" src="./doc/images/overview/PowerLauncher_small.png" />](src/modules/launcher/) [PowerToys Run](src/modules/launcher/) is a new toy in PowerToys that can help you search and launch your app instantly with a simple alt-space and start typing! It is open source and modular for additional plugins. Window Walker is now inside too! This PowerToy requires Windows 10 1903 (build 18362) or later.
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
-->
|
||||
|
||||
### Version 1.0 plan
|
||||
|
||||
Our plan for all the [goals and utilities for v1.0 detailed over here in the wiki][v1].
|
||||
|
||||
## Installing and running Microsoft PowerToys
|
||||
|
||||
👉 **Note:** Microsoft PowerToys requires Windows 10 1803 (build 17134) or later.
|
||||
**Requirements:**
|
||||
- Microsoft PowerToys requires Windows 10 1803 (build 17134) or later.
|
||||
- Have [.NET Core 3.1 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet-core/thank-you/runtime-desktop-3.1.4-windows-x64-installer). The installer will prompt this but we want to directly make people aware.
|
||||
|
||||
### Via Github with MSI [Recommended]
|
||||
|
||||
Install from the [Microsoft PowerToys GitHub releases page][github-release-link]. Click on `Assets` to show the files available in the release and then click on `PowerToysSetup-0.17.0-x64.msi` to download the PowerToys installer.
|
||||
Install from the [Microsoft PowerToys GitHub releases page][github-release-link]. Click on `Assets` to show the files available in the release and then click on `PowerToysSetup-0.18.1-x64.msi` to download the PowerToys installer.
|
||||
|
||||
**Note:** After installing, you will have to start PowerToys for the first time. We will improve install experience this moving forward but due to a possible install dependency, we can't start after install currently.
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
### Via WinGet (Preview)
|
||||
Download PowerToys from [WinGet](https://github.com/microsoft/winget-cli/releases). To install PowerToys, run the following command from the command line / PowerShell:
|
||||
|
||||
```powershell
|
||||
WinGet install powertoys
|
||||
```
|
||||
|
||||
### Other install methods
|
||||
|
||||
#### Via Chocolatey - ⚠ Unofficial ⚠
|
||||
#### Via Chocolatey (Unofficial)
|
||||
|
||||
Download and upgrade PowerToys from [Chocolatey](https://chocolatey.org). If you have any issues when installing/upgrading the package please go to the [package page](https://chocolatey.org/packages/powertoys) and follow the [Chocolatey triage process](https://chocolatey.org/docs/package-triage-process)
|
||||
|
||||
@@ -117,29 +118,30 @@ We currently support the matrix below.
|
||||
|
||||
## What's Happening
|
||||
|
||||
### April 2020 Update
|
||||
### May 2020 Update
|
||||
|
||||
Our goals for 0.17 release cycle were updatability and stability.
|
||||
Our goals for 0.18 release cycle was three big items, PowerToys Run, Keyboard manager, and migrating to the new settings system. This is also the first time we'll test out the auto-updating system.
|
||||
|
||||
**Auto-updating:** We just added in the code for doing updating, so the first chance to experience this will be when 0.18 is released. We’re also seeing how aggressive everyone wants with this so right now, you’ll have to click “Install” for it to kick off the installer. This is something we’d love feedback on.
|
||||
Feedback is critical. We know there are areas for improvement on PT Run. We would love feedback so we can improve. We also would love to know if you want us to be more aggressive on auto-upgrading.
|
||||
|
||||
Another thing we did was utilized telemetry from PowerToys to prioritize virtual desktop FancyZone work. We knew there was a subset of bugs caused by an underlying issue and seeing how many users it affected helped us reprioritize to do the work sooner.
|
||||
|
||||
- We shipped [v0.17][github-release-link]!
|
||||
- Auto-updating
|
||||
- FancyZone improvement:
|
||||
- Virtual desktop support should be much better!
|
||||
- Better taskbar positioning
|
||||
- Fixed non-admin install regression.
|
||||
- We shipped [v0.18][github-release-link]!
|
||||
- New Utilities
|
||||
- PowerToys Run, our new application launcher (use alt-space to activate)
|
||||
- Keyboard manager, a quick easy way to remap your keyboard
|
||||
- Fixed [#243](https://github.com/microsoft/PowerToys/issues/243)'s setting issue
|
||||
- Improved performance on FancyZones [#1264](https://github.com/microsoft/PowerToys/issues/1264)
|
||||
- Lots of bug fixes!
|
||||
|
||||
For [0.18](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F4), we are proactively working on:
|
||||
For [0.19](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F4), we are proactively working on:
|
||||
|
||||
- Win+R replacement (Launcher)
|
||||
- Keyboard remapping
|
||||
- Enable PT Run to be mapped to Win-Keys
|
||||
- Stability / tech debt fixes
|
||||
- Performance improvements with FancyZones
|
||||
- A testing utility for FancyZones to be sure we can test different window configurations.
|
||||
- Settings v2 / Fix bug #243
|
||||
|
||||
### Version 1.0 plan
|
||||
|
||||
Our plan for all the [goals and utilities for v1.0 detailed over here in the wiki][v1].
|
||||
|
||||
## Developer Guidance
|
||||
|
||||
|
||||
@@ -69,75 +69,11 @@
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\WiX.3.11.2\build\wix.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WiX.3.11.2\build\wix.props'))" />
|
||||
</Target>
|
||||
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>setlocal enableDelayedExpansion
|
||||
|
||||
rem Publish Settings
|
||||
SET settingsProfileFolderName=..\..\..\..\src\core\Microsoft.PowerToys.Settings.UI.Runner\Properties\PublishProfiles\
|
||||
rem Create the publish profile folder if it doesn%27t exist
|
||||
IF NOT EXIST !settingsProfileFolderName! (mkdir !settingsProfileFolderName!)
|
||||
SET settingsProfileFileName=SettingsProfile.pubxml
|
||||
SET settingsPublishProfile=!settingsProfileFolderName!!settingsProfileFileName!
|
||||
|
||||
rem Create the publish profile pubxml
|
||||
echo ^<%3fxml version="1.0" encoding="utf-8"%3f^> > !settingsPublishProfile!
|
||||
echo ^<^^!-- >> !settingsPublishProfile!
|
||||
echo https://go.microsoft.com/fwlink/%3fLinkID=208121. >> !settingsPublishProfile!
|
||||
echo --^> >> !settingsPublishProfile!
|
||||
echo ^<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"^> >> !settingsPublishProfile!
|
||||
echo ^<PropertyGroup^> >> !settingsPublishProfile!
|
||||
echo ^<PublishProtocol^>FileSystem^</PublishProtocol^> >> !settingsPublishProfile!
|
||||
echo ^<Configuration^>$(ConfigurationName)^</Configuration^> >> !settingsPublishProfile!
|
||||
echo ^<Platform^>$(PlatformName)^</Platform^> >> !settingsPublishProfile!
|
||||
echo ^<TargetFramework^>netcoreapp3.1^</TargetFramework^> >> !settingsPublishProfile!
|
||||
echo ^<PublishDir^>..\..\..\$(PlatformName)\$(ConfigurationName)\SettingsUIRunner^</PublishDir^> >> !settingsPublishProfile!
|
||||
echo ^<RuntimeIdentifier^>win-x64^</RuntimeIdentifier^> >> !settingsPublishProfile!
|
||||
echo ^<SelfContained^>false^</SelfContained^> >> !settingsPublishProfile!
|
||||
echo ^<PublishSingleFile^>False^</PublishSingleFile^> >> !settingsPublishProfile!
|
||||
echo ^<PublishReadyToRun^>False^</PublishReadyToRun^> >> !settingsPublishProfile!
|
||||
echo ^</PropertyGroup^> >> !settingsPublishProfile!
|
||||
echo ^</Project^> >> !settingsPublishProfile!
|
||||
|
||||
rem In case of Release we should not use Debug CRT in VCRT forwarders
|
||||
IF $(ConfigurationName)==Release (
|
||||
"$(MSBuildBinPath)\msbuild.exe" ..\..\..\..\src\core\Microsoft.PowerToys.Settings.UI.Runner\Microsoft.PowerToys.Settings.UI.Runner.csproj -t:Publish -p:Configuration="$(ConfigurationName)" -p:Platform="$(PlatformName)" -p:AppxBundle=Never -p:VCRTForwarders-IncludeDebugCRT=false -p:PublishProfile=!settingsProfileFileName!
|
||||
) ELSE (
|
||||
"$(MSBuildBinPath)\msbuild.exe" ..\..\..\..\src\core\Microsoft.PowerToys.Settings.UI.Runner\Microsoft.PowerToys.Settings.UI.Runner.csproj -t:Publish -p:Configuration="$(ConfigurationName)" -p:Platform="$(PlatformName)" -p:AppxBundle=Never -p:PublishProfile=!settingsProfileFileName!
|
||||
)
|
||||
|
||||
rem Publish Launcher
|
||||
SET launcherProfileFolderName=..\..\..\..\src\modules\launcher\PowerLauncher\Properties\PublishProfiles\
|
||||
|
||||
rem Create the publish profile folder if it doesn%27t exist
|
||||
IF NOT EXIST !launcherProfileFolderName! (mkdir !launcherProfileFolderName!)
|
||||
SET launcherProfileFileName=LauncherProfile.pubxml
|
||||
SET launcherPublishProfile=!launcherProfileFolderName!!launcherProfileFileName!
|
||||
|
||||
rem Create the publish profile pubxml
|
||||
echo ^<%3fxml version="1.0" encoding="utf-8"%3f^> > !launcherPublishProfile!
|
||||
echo ^<^^!-- >> !launcherPublishProfile!
|
||||
echo https://go.microsoft.com/fwlink/%3fLinkID=208121. >> !launcherPublishProfile!
|
||||
echo --^> >> !launcherPublishProfile!
|
||||
echo ^<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"^> >> !launcherPublishProfile!
|
||||
echo ^<PropertyGroup^> >> !launcherPublishProfile!
|
||||
echo ^<PublishProtocol^>FileSystem^</PublishProtocol^> >> !launcherPublishProfile!
|
||||
echo ^<Configuration^>$(ConfigurationName)^</Configuration^> >> !launcherPublishProfile!
|
||||
echo ^<Platform^>$(PlatformName)^</Platform^> >> !launcherPublishProfile!
|
||||
echo ^<TargetFramework^>netcoreapp3.1^</TargetFramework^> >> !launcherPublishProfile!
|
||||
echo ^<PublishDir^>..\..\..\..\$(PlatformName)\$(ConfigurationName)\modules\launcher^</PublishDir^> >> !launcherPublishProfile!
|
||||
echo ^<RuntimeIdentifier^>win-x64^</RuntimeIdentifier^> >> !launcherPublishProfile!
|
||||
echo ^<SelfContained^>false^</SelfContained^> >> !launcherPublishProfile!
|
||||
echo ^<PublishSingleFile^>False^</PublishSingleFile^> >> !launcherPublishProfile!
|
||||
echo ^<PublishReadyToRun^>False^</PublishReadyToRun^> >> !launcherPublishProfile!
|
||||
echo ^</PropertyGroup^> >> !launcherPublishProfile!
|
||||
echo ^</Project^> >> !launcherPublishProfile!
|
||||
|
||||
rem In case of Release we should not use Debug CRT in VCRT forwarders
|
||||
IF $(ConfigurationName)==Release (
|
||||
"$(MSBuildBinPath)\msbuild.exe" ..\..\..\..\src\modules\launcher\PowerLauncher\PowerLauncher.csproj -t:Publish -p:Configuration="$(ConfigurationName)" -p:Platform="$(PlatformName)" -p:AppxBundle=Never -p:VCRTForwarders-IncludeDebugCRT=false -p:PublishProfile=!launcherProfileFileName!
|
||||
) ELSE (
|
||||
"$(MSBuildBinPath)\msbuild.exe" ..\..\..\..\src\modules\launcher\PowerLauncher\PowerLauncher.csproj -t:Publish -p:Configuration="$(ConfigurationName)" -p:Platform="$(PlatformName)" -p:AppxBundle=Never -p:PublishProfile=!launcherProfileFileName!
|
||||
<PreBuildEvent>IF NOT DEFINED IsPipeline (
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0
|
||||
SET PTRoot=..\..\..\..
|
||||
call "..\..\publish.cmd"
|
||||
)</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!--
|
||||
|
||||
63
installer/PowerToysSetup/publish.cmd
Normal file
63
installer/PowerToysSetup/publish.cmd
Normal file
@@ -0,0 +1,63 @@
|
||||
setlocal enableDelayedExpansion
|
||||
|
||||
IF NOT DEFINED PTRoot (SET PTRoot=..\..)
|
||||
|
||||
rem Publish Settings
|
||||
SET settingsProfileFolderName=!PTRoot!\src\core\Microsoft.PowerToys.Settings.UI.Runner\Properties\PublishProfiles\
|
||||
rem Create the publish profile folder if it doesn't exist
|
||||
IF NOT EXIST !settingsProfileFolderName! (mkdir !settingsProfileFolderName!)
|
||||
SET settingsProfileFileName=SettingsProfile.pubxml
|
||||
SET settingsPublishProfile=!settingsProfileFolderName!!settingsProfileFileName!
|
||||
|
||||
rem Create the publish profile pubxml
|
||||
echo ^<?xml version="1.0" encoding="utf-8"?^> > !settingsPublishProfile!
|
||||
echo ^<^^!-- >> !settingsPublishProfile!
|
||||
echo https://go.microsoft.com/fwlink/?LinkID=208121. >> !settingsPublishProfile!
|
||||
echo --^> >> !settingsPublishProfile!
|
||||
echo ^<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"^> >> !settingsPublishProfile!
|
||||
echo ^<PropertyGroup^> >> !settingsPublishProfile!
|
||||
echo ^<PublishProtocol^>FileSystem^</PublishProtocol^> >> !settingsPublishProfile!
|
||||
echo ^<Configuration^>Release^</Configuration^> >> !settingsPublishProfile!
|
||||
echo ^<Platform^>x64^</Platform^> >> !settingsPublishProfile!
|
||||
echo ^<TargetFramework^>netcoreapp3.1^</TargetFramework^> >> !settingsPublishProfile!
|
||||
echo ^<PublishDir^>..\..\..\x64\Release\SettingsUIRunner^</PublishDir^> >> !settingsPublishProfile!
|
||||
echo ^<RuntimeIdentifier^>win-x64^</RuntimeIdentifier^> >> !settingsPublishProfile!
|
||||
echo ^<SelfContained^>false^</SelfContained^> >> !settingsPublishProfile!
|
||||
echo ^<PublishSingleFile^>False^</PublishSingleFile^> >> !settingsPublishProfile!
|
||||
echo ^<PublishReadyToRun^>False^</PublishReadyToRun^> >> !settingsPublishProfile!
|
||||
echo ^</PropertyGroup^> >> !settingsPublishProfile!
|
||||
echo ^</Project^> >> !settingsPublishProfile!
|
||||
|
||||
rem In case of Release we should not use Debug CRT in VCRT forwarders
|
||||
msbuild !PTRoot!\src\core\Microsoft.PowerToys.Settings.UI.Runner\Microsoft.PowerToys.Settings.UI.Runner.csproj -t:Publish -p:Configuration="Release" -p:Platform="x64" -p:AppxBundle=Never -p:VCRTForwarders-IncludeDebugCRT=false -p:PublishProfile=!settingsProfileFileName!
|
||||
|
||||
|
||||
rem Publish Launcher
|
||||
SET launcherProfileFolderName=!PTRoot!\src\modules\launcher\PowerLauncher\Properties\PublishProfiles\
|
||||
|
||||
rem Create the publish profile folder if it doesn't exist
|
||||
IF NOT EXIST !launcherProfileFolderName! (mkdir !launcherProfileFolderName!)
|
||||
SET launcherProfileFileName=LauncherProfile.pubxml
|
||||
SET launcherPublishProfile=!launcherProfileFolderName!!launcherProfileFileName!
|
||||
|
||||
rem Create the publish profile pubxml
|
||||
echo ^<?xml version="1.0" encoding="utf-8"?^> > !launcherPublishProfile!
|
||||
echo ^<^^!-- >> !launcherPublishProfile!
|
||||
echo https://go.microsoft.com/fwlink/?LinkID=208121. >> !launcherPublishProfile!
|
||||
echo --^> >> !launcherPublishProfile!
|
||||
echo ^<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"^> >> !launcherPublishProfile!
|
||||
echo ^<PropertyGroup^> >> !launcherPublishProfile!
|
||||
echo ^<PublishProtocol^>FileSystem^</PublishProtocol^> >> !launcherPublishProfile!
|
||||
echo ^<Configuration^>Release^</Configuration^> >> !launcherPublishProfile!
|
||||
echo ^<Platform^>x64^</Platform^> >> !launcherPublishProfile!
|
||||
echo ^<TargetFramework^>netcoreapp3.1^</TargetFramework^> >> !launcherPublishProfile!
|
||||
echo ^<PublishDir^>..\..\..\..\x64\Release\modules\launcher^</PublishDir^> >> !launcherPublishProfile!
|
||||
echo ^<RuntimeIdentifier^>win-x64^</RuntimeIdentifier^> >> !launcherPublishProfile!
|
||||
echo ^<SelfContained^>false^</SelfContained^> >> !launcherPublishProfile!
|
||||
echo ^<PublishSingleFile^>False^</PublishSingleFile^> >> !launcherPublishProfile!
|
||||
echo ^<PublishReadyToRun^>False^</PublishReadyToRun^> >> !launcherPublishProfile!
|
||||
echo ^</PropertyGroup^> >> !launcherPublishProfile!
|
||||
echo ^</Project^> >> !launcherPublishProfile!
|
||||
|
||||
rem In case of Release we should not use Debug CRT in VCRT forwarders
|
||||
msbuild !PTRoot!\src\modules\launcher\PowerLauncher\PowerLauncher.csproj -t:Publish -p:Configuration="Release" -p:Platform="x64" -p:AppxBundle=Never -p:VCRTForwarders-IncludeDebugCRT=false -p:PublishProfile=!launcherProfileFileName!
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Version>0.18.0</Version>
|
||||
<Version>0.18.2</Version>
|
||||
<DefineConstants>Version=$(Version);</DefineConstants>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -186,7 +186,25 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
}
|
||||
std::wstring_view action{ args[1] };
|
||||
|
||||
if (action == L"-install_dotnet")
|
||||
if (action == L"-start_PowerLauncher")
|
||||
{
|
||||
HANDLE hMapFile = OpenFileMappingW(FILE_MAP_WRITE, FALSE, POWER_LAUNCHER_PID_SHARED_FILE);
|
||||
if (hMapFile)
|
||||
{
|
||||
PDWORD pidBuffer = reinterpret_cast<PDWORD>(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(DWORD)));
|
||||
if (pidBuffer)
|
||||
{
|
||||
*pidBuffer = 0;
|
||||
run_same_elevation(L"modules\\launcher\\PowerLauncher.exe", L"", pidBuffer);
|
||||
FlushViewOfFile(pidBuffer, sizeof(DWORD));
|
||||
UnmapViewOfFile(pidBuffer);
|
||||
}
|
||||
|
||||
FlushFileBuffers(hMapFile);
|
||||
CloseHandle(hMapFile);
|
||||
}
|
||||
}
|
||||
else if (action == L"-install_dotnet")
|
||||
{
|
||||
if (dotnet_is_installed())
|
||||
{
|
||||
|
||||
@@ -461,7 +461,7 @@ bool run_elevated(const std::wstring& file, const std::wstring& params)
|
||||
}
|
||||
}
|
||||
|
||||
bool run_non_elevated(const std::wstring& file, const std::wstring& params)
|
||||
bool run_non_elevated(const std::wstring& file, const std::wstring& params, DWORD* returnPid)
|
||||
{
|
||||
auto executable_args = L"\"" + file + L"\"";
|
||||
if (!params.empty())
|
||||
@@ -510,8 +510,8 @@ bool run_non_elevated(const std::wstring& file, const std::wstring& params)
|
||||
siex.lpAttributeList = pptal;
|
||||
siex.StartupInfo.cb = sizeof(siex);
|
||||
|
||||
PROCESS_INFORMATION process_info = { 0 };
|
||||
auto succedded = CreateProcessW(file.c_str(),
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
auto succeeded = CreateProcessW(file.c_str(),
|
||||
const_cast<LPWSTR>(executable_args.c_str()),
|
||||
nullptr,
|
||||
nullptr,
|
||||
@@ -520,28 +520,38 @@ bool run_non_elevated(const std::wstring& file, const std::wstring& params)
|
||||
nullptr,
|
||||
nullptr,
|
||||
&siex.StartupInfo,
|
||||
&process_info);
|
||||
if (process_info.hProcess)
|
||||
&pi);
|
||||
if (succeeded)
|
||||
{
|
||||
CloseHandle(process_info.hProcess);
|
||||
if (pi.hProcess)
|
||||
{
|
||||
if (returnPid)
|
||||
{
|
||||
*returnPid = GetProcessId(pi.hProcess);
|
||||
}
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
if (pi.hThread)
|
||||
{
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
}
|
||||
if (process_info.hThread)
|
||||
{
|
||||
CloseHandle(process_info.hThread);
|
||||
}
|
||||
return succedded;
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
bool run_same_elevation(const std::wstring& file, const std::wstring& params)
|
||||
bool run_same_elevation(const std::wstring& file, const std::wstring& params, DWORD* returnPid)
|
||||
{
|
||||
auto executable_args = L"\"" + file + L"\"";
|
||||
if (!params.empty())
|
||||
{
|
||||
executable_args += L" " + params;
|
||||
}
|
||||
|
||||
STARTUPINFO si = { 0 };
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
auto succedded = CreateProcessW(file.c_str(),
|
||||
auto succeeded = CreateProcessW(file.c_str(),
|
||||
const_cast<LPWSTR>(executable_args.c_str()),
|
||||
nullptr,
|
||||
nullptr,
|
||||
@@ -551,15 +561,26 @@ bool run_same_elevation(const std::wstring& file, const std::wstring& params)
|
||||
nullptr,
|
||||
&si,
|
||||
&pi);
|
||||
if (pi.hProcess)
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
CloseHandle(pi.hProcess);
|
||||
if (pi.hProcess)
|
||||
{
|
||||
if (returnPid)
|
||||
{
|
||||
*returnPid = GetProcessId(pi.hProcess);
|
||||
}
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
|
||||
if (pi.hThread)
|
||||
{
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
}
|
||||
if (pi.hThread)
|
||||
{
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
return succedded;
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
std::wstring get_process_path(HWND window) noexcept
|
||||
|
||||
@@ -69,11 +69,11 @@ bool drop_elevated_privileges();
|
||||
// Run command as elevated user, returns true if succeeded
|
||||
bool run_elevated(const std::wstring& file, const std::wstring& params);
|
||||
|
||||
// Run command as non-elevated user, returns true if succeeded
|
||||
bool run_non_elevated(const std::wstring& file, const std::wstring& params);
|
||||
// Run command as non-elevated user, returns true if succeeded, puts the process id into returnPid if returnPid != NULL
|
||||
bool run_non_elevated(const std::wstring& file, const std::wstring& params, DWORD* returnPid);
|
||||
|
||||
// Run command with the same elevation, returns true if succedded
|
||||
bool run_same_elevation(const std::wstring& file, const std::wstring& params);
|
||||
// Run command with the same elevation, returns true if succeeded
|
||||
bool run_same_elevation(const std::wstring& file, const std::wstring& params, DWORD* returnPid);
|
||||
|
||||
// Returns true if the current process is running from administrator account
|
||||
bool check_user_is_admin();
|
||||
@@ -136,3 +136,5 @@ struct overloaded : Ts...
|
||||
};
|
||||
template<class... Ts>
|
||||
overloaded(Ts...)->overloaded<Ts...>;
|
||||
|
||||
#define POWER_LAUNCHER_PID_SHARED_FILE L"Local\\3cbfbad4-199b-4e2c-9825-942d5d3d3c74"
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Microsoft.PowerLauncher.Telemetry
|
||||
/// <summary>
|
||||
/// Gets The version string. TODO: This should be replaced by a P/Invoke call to get_product_version
|
||||
/// </summary>
|
||||
public string Version => "v0.18.0";
|
||||
public string Version => "v0.18.2";
|
||||
|
||||
public double BootTimeMs { get; set; }
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<RepositoryUrl>https://github.com/microsoft/PowerToys</RepositoryUrl>
|
||||
<RepositoryType>Github</RepositoryType>
|
||||
<PackageTags>PowerToys</PackageTags>
|
||||
<Version>0.15.2.0</Version>
|
||||
<Version>0.18.2.0</Version>
|
||||
<Platforms>x64</Platforms>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
<Win32Resource />
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity
|
||||
Name="f4f787a5-f0ae-47a9-be89-5408b1dd2b47"
|
||||
Publisher="CN=lamotile"
|
||||
Version="0.15.2.0" />
|
||||
Version="0.18.2.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="f4f787a5-f0ae-47a9-be89-5408b1dd2b47" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -573,7 +573,7 @@
|
||||
<value>About Shortcut Guide</value>
|
||||
</data>
|
||||
<data name="General_Repository.Text" xml:space="preserve">
|
||||
<value>Github repository</value>
|
||||
<value>GitHub repository</value>
|
||||
</data>
|
||||
<data name="General_Updates.Text" xml:space="preserve">
|
||||
<value>Updates</value>
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
# Introduction
|
||||
Super FancyZones! Just like FancyZones except super.
|
||||
|
||||
# Getting Started
|
||||
Grab FancyZones.exe from the bin directory or \\\\wexfs\users\bretan\proto\superfancyzones and run it
|
||||
|
||||
## Dragging windows
|
||||
* While dragging a window around, zones will appear that the window can be dropped in. Dropping the window in a zone will position it in the zone.
|
||||
* While dragging a window, you can hit number keys to cycle the active zone set. Eg, drag a window around and hit the '3' key will change to a zone set with 3 zones.
|
||||
|
||||
## Hotkeys
|
||||
* Win+~ - opens the zone viewer/editor
|
||||
* Win+ctrl+number - cycle through layouts with the corresponding number of zones (only if Override snap hotkeys setting is enabled)
|
||||
* Win+left arrow, Win+right arrow - move foreground window between zones
|
||||
|
||||
## Zone Viewer/Editor (Win + ~)
|
||||
* Hitting a number key cycles through layouts matching the number of zones (eg 3 cycles through layouts with 3 zones)
|
||||
* R resets the focused monitor back to defaults
|
||||
* C clears the current layout so you can start fresh
|
||||
* W opens a dialog to choose wallpaper
|
||||
* Left click moves the zone to the top
|
||||
* Right click moves the zone to the bottom
|
||||
|
||||
### E enters editor mode (hit E or Escape to exit editor mode)
|
||||
* Left/Right/Up/Down arrows adjust the grid spacing
|
||||
* PgUp/PgDn adjust grid margins
|
||||
* Ctrl+left click splits the clicked zone in half horizontally
|
||||
* Ctrl+right click splits the clicked zone in half vertically
|
||||
|
||||
# Options
|
||||
### Default Drag Mode
|
||||
* None - don't do anything when dragging windows around (shift enters normal mode, ctrl enters adjusted mode)
|
||||
* Normal - show zones when dragging windows around (shift disables, ctrl enters adjusted mode)
|
||||
* Adjusted - show zones when dragging windows around with an accelerated cursor
|
||||
|
||||
### Display change
|
||||
* Move windows - automatically move windows around when display changes
|
||||
|
||||
### Virtual Desktop change
|
||||
* Move windows - automatically move windows around when virtual desktop changes
|
||||
* Change wallpaper - use custom wallpaper per-monitor per-desktop
|
||||
* Flash zones - flash zones on each monitor
|
||||
|
||||
### Miscellaneous
|
||||
* Override snap hotkeys - steal hotkeys normally used by shell (win+left/right, win+ctrl+num)
|
||||
* Colorful zones - use colored zones in zone viewer
|
||||
|
||||
# Known issues
|
||||
* See open bugs for full list of issues
|
||||
* Win+left and Win+right don't move between monitors
|
||||
* If you use Virtual Desktops, make sure to perform at least one virtual desktop switch before launching the fancyzones (it relies on a volatile regkey that explorer writes)
|
||||
* Sometimes you have to click on a zone viewer window before it gets keyboard focus when opening views with Win+~
|
||||
* Quickly switching virtual desktops with win+ctrl+arrow hotkeys can crash fancyzones
|
||||
@@ -55,14 +55,6 @@ public:
|
||||
IFACEMETHODIMP_(void)
|
||||
Destroy() noexcept;
|
||||
|
||||
// IFancyZonesCallback
|
||||
IFACEMETHODIMP_(bool)
|
||||
InMoveSize() noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
return m_windowMoveHandler.InMoveSize();
|
||||
}
|
||||
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
@@ -185,6 +177,13 @@ public:
|
||||
return m_settings->GetSettings()->makeDraggedWindowTransparent;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
InMoveSize() noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
return m_windowMoveHandler.InMoveSize();
|
||||
}
|
||||
|
||||
LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
|
||||
void OnDisplayChange(DisplayChangeType changeType) noexcept;
|
||||
void AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept;
|
||||
|
||||
@@ -81,9 +81,13 @@ interface __declspec(uuid("{5C8D99D6-34B2-4F4A-A8E5-7483F6869775}")) IZoneWindow
|
||||
*/
|
||||
IFACEMETHOD_(int, GetZoneHighlightOpacity)() = 0;
|
||||
/**
|
||||
* @returns Bool indicating if dragged window should be transparrent
|
||||
* @returns Boolean indicating if dragged window should be transparrent.
|
||||
*/
|
||||
IFACEMETHOD_(bool, isMakeDraggedWindowTransparentActive) () = 0;
|
||||
/**
|
||||
* @returns Boolean indicating if move/size operation is currently active.
|
||||
*/
|
||||
IFACEMETHOD_(bool, InMoveSize) () = 0;
|
||||
};
|
||||
|
||||
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings) noexcept;
|
||||
|
||||
@@ -522,6 +522,10 @@ ZoneWindow::ShowZoneWindow() noexcept
|
||||
std::thread{ [=]() {
|
||||
AnimateWindow(window, m_showAnimationDuration, AW_BLEND);
|
||||
InvalidateRect(window, nullptr, true);
|
||||
if (!m_host->InMoveSize())
|
||||
{
|
||||
HideZoneWindow();
|
||||
}
|
||||
} }.detach();
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ namespace FancyZonesUnitTests
|
||||
{
|
||||
return true;
|
||||
}
|
||||
IFACEMETHODIMP_(bool)
|
||||
InMoveSize() noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
IZoneWindow* m_zoneWindow;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
Taking to long to process the events has negative impact on the whole system
|
||||
Taking too long to process the events has negative impact on the whole system
|
||||
performance. To address this, the events are signaled from a different
|
||||
thread, not from the event hook callback itself.
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,7 @@ To create mappings with Keyboard Manager, you have the option of launching eithe
|
||||
|
||||
|
||||
## 1.2 Remap Keys
|
||||
To remap a key to another key, click the <kbd>Remap a Key</kbd> button to launch the Remap Keyboard UI. When first launched, you are met with no predefined mappings and must click the <kbd>+</kbd> button to add a new remap. From there, select the key whose output you want to ***change*** as the “Original Key” and then keys new output as the “New Key”. For example, if you want to press <kbd>A</kbd> and have <kbd>B</kbd> appear, Key <kbd>A</kbd> would be your “Original Key” and Key <kbd>B</kbd> would be your “New Key”. If you want to swap keys, add another remapping with Key <kbd>B</kbd> as your Original and Key <kbd>A</kbd> as your New.
|
||||
To remap a key to another key, click the <kbd>Remap a Key</kbd> button to launch the Remap Keyboard UI. When first launched, you are met with no predefined mappings and must click the <kbd>+</kbd> button to add a new remap. From there, select the key whose output you want to ***change*** as the “Key” and then keys new output as the “Mapped To”. For example, if you want to press <kbd>A</kbd> and have <kbd>B</kbd> appear, Key <kbd>A</kbd> would be your “Key” and Key <kbd>B</kbd> would be your “Mapped To" key. If you want to swap keys, add another remapping with Key <kbd>B</kbd> as your "Key" and Key <kbd>A</kbd> as your "Mapped To".
|
||||
|
||||
![alt text][remapkey]
|
||||
|
||||
@@ -19,8 +19,8 @@ To remap a key to another key, click the <kbd>Remap a Key</kbd> button to launch
|
||||
Currently you are only able to remap global level shortcuts (they apply to your whole OS), but **app-specific shortcuts are coming soon!**
|
||||
|
||||
To change how you invoke a particular shortcut, click the <kbd>Remap a shortcut</kbd> button to
|
||||
launch the Remap Shortcuts UI. When first launched, you are met with no predefined mappings and must click the <kbd>+</kbd> button to add a new remap. The Original shortcut is the shortcut you want to change and the New Shortcut is the shortcut you want to change it
|
||||
to. Ex. If you want <kbd>Ctrl</kbd>+<kbd>C</kbd> to paste, <kbd>Ctrl</kbd>+<kbd>C</kbd> is the Original Shortcut and <kbd>Ctrl</kbd>+<kbd>V</kbd> is the New Shortcut. Here are a few rules to shortcuts as you get started:
|
||||
launch the Remap Shortcuts UI. When first launched, you are met with no predefined mappings and must click the <kbd>+</kbd> button to add a new remap. The "Shortcut" is the shortcut you want to change and the "Mapped To" is the shortcut you want to change it
|
||||
to. Ex. If you want <kbd>Ctrl</kbd>+<kbd>C</kbd> to paste, <kbd>Ctrl</kbd>+<kbd>C</kbd> is the "Shortcut" and <kbd>Ctrl</kbd>+<kbd>V</kbd> is the "Mapped To". Here are a few rules to shortcuts as you get started:
|
||||
|
||||
- Shortcuts must begin with a modifier key (<kbd>Ctrl</kbd>, <kbd>Shift</kbd>, <kbd>Alt</kbd>, <kbd>![alt text][winlogo]</kbd>)
|
||||
- Shortcuts must end with an action key (all non-modifier keys)
|
||||
|
||||
@@ -38,6 +38,16 @@ bool KeyboardManagerState::CheckUIState(KeyboardManagerUIState state)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// If we are checking for EditKeyboardWindowActivated then it's possible the state could be DetectSingleKeyRemapWindowActivated but not in focus
|
||||
else if (state == KeyboardManagerUIState::EditKeyboardWindowActivated && uiState == KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If we are checking for EditShortcutsWindowActivated then it's possible the state could be DetectShortcutWindowActivated but not in focus
|
||||
else if (state == KeyboardManagerUIState::EditShortcutsWindowActivated && uiState == KeyboardManagerUIState::DetectShortcutWindowActivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -232,13 +232,13 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
|
||||
|
||||
// Text block for information about remap key section.
|
||||
TextBlock keyRemapInfoHeader;
|
||||
keyRemapInfoHeader.Text(L"Select the key you want to change (Original Key) and the key you want it to become (New Key).");
|
||||
keyRemapInfoHeader.Text(L"Select the key you want to change (Key) and the key you want it to become (Mapped To).");
|
||||
keyRemapInfoHeader.Margin({ 10, 0, 0, 10 });
|
||||
keyRemapInfoHeader.FontWeight(Text::FontWeights::SemiBold());
|
||||
keyRemapInfoHeader.TextWrapping(TextWrapping::Wrap);
|
||||
|
||||
TextBlock keyRemapInfoExample;
|
||||
keyRemapInfoExample.Text(L"For example, if you want to press A and get B, Key A would be your \"Original Key\" and Key B would be your \"New Key\".");
|
||||
keyRemapInfoExample.Text(L"For example, if you want to press A and get B, Key A would be your \"Key\" and Key B would be your \"Mapped To\".");
|
||||
keyRemapInfoExample.Margin({ 10, 0, 0, 20 });
|
||||
keyRemapInfoExample.FontStyle(Text::FontStyle::Italic);
|
||||
keyRemapInfoExample.TextWrapping(TextWrapping::Wrap);
|
||||
@@ -265,13 +265,13 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
|
||||
|
||||
// First header textblock in the header row of the keys remap table
|
||||
TextBlock originalKeyRemapHeader;
|
||||
originalKeyRemapHeader.Text(L"Original Key:");
|
||||
originalKeyRemapHeader.Text(L"Key:");
|
||||
originalKeyRemapHeader.FontWeight(Text::FontWeights::Bold());
|
||||
originalKeyRemapHeader.Margin({ 0, 0, 0, 10 });
|
||||
|
||||
// Second header textblock in the header row of the keys remap table
|
||||
TextBlock newKeyRemapHeader;
|
||||
newKeyRemapHeader.Text(L"New Key:");
|
||||
newKeyRemapHeader.Text(L"Mapped To:");
|
||||
newKeyRemapHeader.FontWeight(Text::FontWeights::Bold());
|
||||
newKeyRemapHeader.Margin({ 0, 0, 0, 10 });
|
||||
|
||||
|
||||
@@ -144,13 +144,13 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
|
||||
|
||||
// Text block for information about remap key section.
|
||||
TextBlock shortcutRemapInfoHeader;
|
||||
shortcutRemapInfoHeader.Text(L"Select shortcut you want to change (Original Shortcut) and the shortcut (New Shortcut) you want it to invoke.");
|
||||
shortcutRemapInfoHeader.Text(L"Select shortcut you want to change (Shortcut) and the shortcut you want it to invoke (Mapped To).");
|
||||
shortcutRemapInfoHeader.Margin({ 10, 0, 0, 10 });
|
||||
shortcutRemapInfoHeader.FontWeight(Text::FontWeights::SemiBold());
|
||||
shortcutRemapInfoHeader.TextWrapping(TextWrapping::Wrap);
|
||||
|
||||
TextBlock shortcutRemapInfoExample;
|
||||
shortcutRemapInfoExample.Text(L"For example, if you want Ctrl+C to paste, Ctrl+C is the Original Shortcut and Ctrl+V is the New Shortcut.");
|
||||
shortcutRemapInfoExample.Text(L"For example, if you want Ctrl+C to paste, Ctrl+C is the \"Shortcut\" and Ctrl+V would be your \"Mapped To\".");
|
||||
shortcutRemapInfoExample.Margin({ 10, 0, 0, 20 });
|
||||
shortcutRemapInfoExample.FontStyle(Text::FontStyle::Italic);
|
||||
shortcutRemapInfoExample.TextWrapping(TextWrapping::Wrap);
|
||||
@@ -178,13 +178,13 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
|
||||
|
||||
// First header textblock in the header row of the shortcut table
|
||||
TextBlock originalShortcutHeader;
|
||||
originalShortcutHeader.Text(L"Original Shortcut:");
|
||||
originalShortcutHeader.Text(L"Shortcut:");
|
||||
originalShortcutHeader.FontWeight(Text::FontWeights::Bold());
|
||||
originalShortcutHeader.Margin({ 0, 0, 0, 10 });
|
||||
|
||||
// Second header textblock in the header row of the shortcut table
|
||||
TextBlock newShortcutHeader;
|
||||
newShortcutHeader.Text(L"New Shortcut:");
|
||||
newShortcutHeader.Text(L"Mapped To:");
|
||||
newShortcutHeader.FontWeight(Text::FontWeights::Bold());
|
||||
newShortcutHeader.Margin({ 0, 0, 0, 10 });
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <interface/lowlevel_keyboard_event_data.h>
|
||||
#include <interface/win_hook_event_data.h>
|
||||
#include <common/settings_objects.h>
|
||||
#include <common/common.h>
|
||||
#include "trace.h"
|
||||
#include "resource.h"
|
||||
|
||||
@@ -131,13 +132,49 @@ public:
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
SHELLEXECUTEINFO sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
sei.lpFile = L"modules\\launcher\\PowerLauncher.exe";
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
ShellExecuteEx(&sei);
|
||||
if (!is_process_elevated(false))
|
||||
{
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
sei.lpFile = L"modules\\launcher\\PowerLauncher.exe";
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
ShellExecuteExW(&sei);
|
||||
|
||||
m_hProcess = sei.hProcess;
|
||||
m_hProcess = sei.hProcess;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wstring action_runner_path = get_module_folderpath();
|
||||
action_runner_path += L"\\action_runner.exe";
|
||||
|
||||
// Set up the shared file from which to retrieve the PID of PowerLauncher
|
||||
HANDLE hMapFile = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(DWORD), POWER_LAUNCHER_PID_SHARED_FILE);
|
||||
if (hMapFile)
|
||||
{
|
||||
PDWORD pidBuffer = reinterpret_cast<PDWORD>(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(DWORD)));
|
||||
if (pidBuffer)
|
||||
{
|
||||
*pidBuffer = 0;
|
||||
m_hProcess = NULL;
|
||||
|
||||
if (run_non_elevated(action_runner_path, L"-start_PowerLauncher", nullptr))
|
||||
{
|
||||
const int maxRetries = 20;
|
||||
for (int retry = 0; retry < maxRetries; ++retry)
|
||||
{
|
||||
Sleep(50);
|
||||
DWORD pid = *pidBuffer;
|
||||
if (pid)
|
||||
{
|
||||
m_hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(hMapFile);
|
||||
}
|
||||
}
|
||||
|
||||
m_enabled = true;
|
||||
}
|
||||
|
||||
@@ -36,11 +36,12 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
|
||||
{
|
||||
while (WDSResults.Read())
|
||||
{
|
||||
if(WDSResults.GetValue(0) != DBNull.Value && WDSResults.GetValue(1) != DBNull.Value)
|
||||
if (WDSResults.GetValue(0) != DBNull.Value && WDSResults.GetValue(1) != DBNull.Value)
|
||||
{
|
||||
var uri_path = new Uri(WDSResults.GetString(0));
|
||||
var result = new SearchResult
|
||||
{
|
||||
Path = WDSResults.GetString(0),
|
||||
Path = uri_path.LocalPath,
|
||||
Title = WDSResults.GetString(1)
|
||||
};
|
||||
_Result.Add(result);
|
||||
@@ -90,7 +91,7 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
|
||||
queryHelper.QueryMaxResults = maxCount;
|
||||
|
||||
// Set list of columns we want to display, getting the path presently
|
||||
queryHelper.QuerySelectColumns = "System.ItemPathDisplay, System.FileName";
|
||||
queryHelper.QuerySelectColumns = "System.ItemUrl, System.FileName";
|
||||
|
||||
// Set additional query restriction
|
||||
queryHelper.QueryWhereRestrictions = "AND scope='file:'";
|
||||
|
||||
@@ -279,7 +279,7 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
|
||||
var result = new Result
|
||||
{
|
||||
SubTitle = "UWP application",
|
||||
SubTitle = "Packaged application",
|
||||
Icon = Logo,
|
||||
Score = score,
|
||||
ContextData = this,
|
||||
@@ -449,6 +449,10 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
parsed = prefix + "//" + key;
|
||||
}
|
||||
else if (key.Contains("resources", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
parsed = prefix + key;
|
||||
}
|
||||
else
|
||||
{
|
||||
parsed = prefix + "///resources/" + key;
|
||||
|
||||
@@ -443,6 +443,46 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
return entry;
|
||||
}
|
||||
|
||||
public class removeDuplicatesComparer : IEqualityComparer<Win32>
|
||||
{
|
||||
public bool Equals(Win32 app1, Win32 app2)
|
||||
{
|
||||
|
||||
if(!string.IsNullOrEmpty(app1.Name) && !string.IsNullOrEmpty(app2.Name)
|
||||
&& !string.IsNullOrEmpty(app1.ExecutableName) && !string.IsNullOrEmpty(app2.ExecutableName)
|
||||
&& !string.IsNullOrEmpty(app1.FullPath) && !string.IsNullOrEmpty(app2.FullPath))
|
||||
{
|
||||
return app1.Name.Equals(app2.Name, StringComparison.OrdinalIgnoreCase)
|
||||
&& app1.ExecutableName.Equals(app2.ExecutableName, StringComparison.OrdinalIgnoreCase)
|
||||
&& app1.FullPath.Equals(app2.FullPath, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ref : https://stackoverflow.com/questions/2730865/how-do-i-calculate-a-good-hash-code-for-a-list-of-strings
|
||||
public int GetHashCode(Win32 obj)
|
||||
{
|
||||
int namePrime = 13;
|
||||
int executablePrime = 17;
|
||||
int fullPathPrime = 31;
|
||||
|
||||
int result = 1;
|
||||
result = result * namePrime + obj.Name.GetHashCode();
|
||||
result = result * executablePrime + obj.ExecutableName.GetHashCode();
|
||||
result = result * fullPathPrime + obj.FullPath.GetHashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Deduplication code
|
||||
public static Func<ParallelQuery<Win32>, Win32[]> DeduplicatePrograms = (programs) =>
|
||||
{
|
||||
var uniqueExePrograms = programs.Where(x => !string.IsNullOrEmpty(x.LnkResolvedPath) || Extension(x.FullPath) != ExeExtension);
|
||||
var uniquePrograms = uniqueExePrograms.Distinct(new removeDuplicatesComparer());
|
||||
return uniquePrograms.ToArray();
|
||||
};
|
||||
|
||||
public static Win32[] All(Settings settings)
|
||||
{
|
||||
try
|
||||
@@ -464,15 +504,7 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
programs = programs.Concat(startMenu);
|
||||
}
|
||||
|
||||
var programsWithoutLnk = programs.Where(x => string.IsNullOrEmpty(x.LnkResolvedPath));
|
||||
var programsAsList = programs.ToList();
|
||||
|
||||
foreach(var app in programsWithoutLnk)
|
||||
{
|
||||
programsAsList.RemoveAll(x => (x.FullPath == app.FullPath) && string.IsNullOrEmpty(x.LnkResolvedPath));
|
||||
}
|
||||
|
||||
return programsAsList.ToArray();
|
||||
return DeduplicatePrograms(programs);
|
||||
}
|
||||
#if DEBUG //This is to make developer aware of any unhandled exception and add in handling.
|
||||
catch (Exception e)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Microsoft.PowerLauncher.Telemetry
|
||||
/// <summary>
|
||||
/// TODO: This should be replaced by a P/Invoke call to get_product_version
|
||||
/// </summary>
|
||||
public string Version => "v0.18.0";
|
||||
public string Version => "v0.18.2";
|
||||
|
||||
public double BootTimeMs { get; set; }
|
||||
|
||||
|
||||
@@ -34,6 +34,115 @@
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ListViewItemNoRightTap" TargetType="ListViewItem">
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="Background" Value="{ThemeResource ListViewItemBackground}" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource ListViewItemForeground}" />
|
||||
<Setter Property="TabNavigation" Value="Local" />
|
||||
<Setter Property="IsHoldingEnabled" Value="True" />
|
||||
<Setter Property="IsRightTapEnabled" Value="False" />
|
||||
<Setter Property="Padding" Value="12,0,12,0" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="MinWidth" Value="{ThemeResource ListViewItemMinWidth}" />
|
||||
<Setter Property="MinHeight" Value="{ThemeResource ListViewItemMinHeight}" />
|
||||
<Setter Property="AllowDrop" Value="False" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="FocusVisualMargin" Value="0" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ListViewItem">
|
||||
<ListViewItemPresenter IsRightTapEnabled="False" ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
x:Name="Root"
|
||||
Control.IsTemplateFocusTarget="True"
|
||||
FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
|
||||
SelectionCheckMarkVisualEnabled="{ThemeResource ListViewItemSelectionCheckMarkVisualEnabled}"
|
||||
CheckBrush="{ThemeResource ListViewItemCheckBrush}"
|
||||
CheckBoxBrush="{ThemeResource ListViewItemCheckBoxBrush}"
|
||||
DragBackground="{ThemeResource ListViewItemDragBackground}"
|
||||
DragForeground="{ThemeResource ListViewItemDragForeground}"
|
||||
FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
|
||||
FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
|
||||
PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
|
||||
PointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
|
||||
PointerOverForeground="{ThemeResource ListViewItemForegroundPointerOver}"
|
||||
SelectedBackground="{ThemeResource ListViewItemBackgroundSelected}"
|
||||
SelectedForeground="{ThemeResource ListViewItemForegroundSelected}"
|
||||
SelectedPointerOverBackground="{ThemeResource ListViewItemBackgroundSelectedPointerOver}"
|
||||
PressedBackground="{ThemeResource ListViewItemBackgroundPressed}"
|
||||
SelectedPressedBackground="{ThemeResource ListViewItemBackgroundSelectedPressed}"
|
||||
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
|
||||
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
|
||||
ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
ContentMargin="{TemplateBinding Padding}"
|
||||
CheckMode="{ThemeResource ListViewItemCheckMode}"
|
||||
RevealBackground="{ThemeResource ListViewItemRevealBackground}"
|
||||
RevealBorderThickness="{ThemeResource ListViewItemRevealBorderThemeThickness}"
|
||||
RevealBorderBrush="{ThemeResource ListViewItemRevealBorderBrush}">
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Selected" />
|
||||
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="PointerOverSelected">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PointerOverPressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="PressedSelected">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
</VisualStateGroup>
|
||||
|
||||
<VisualStateGroup x:Name="DisabledStates">
|
||||
<VisualState x:Name="Enabled" />
|
||||
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.RevealBorderThickness" Value="0" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
</VisualStateGroup>
|
||||
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</ListViewItemPresenter>
|
||||
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IconOnlyButton" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource ButtonRevealBackground}" />
|
||||
<!--<Setter Property="Foreground" Value="{ThemeResource PrimaryTextColor}" />-->
|
||||
@@ -50,7 +159,7 @@
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Grid x:Name="RootGrid" Background="Transparent" CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<Grid x:Name="RootGrid" IsRightTapEnabled="False" Background="Transparent" CornerRadius="{TemplateBinding CornerRadius}">
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
@@ -98,7 +207,7 @@
|
||||
</VisualStateGroup>
|
||||
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<ContentPresenter x:Name="ContentPresenter" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" CornerRadius="{TemplateBinding CornerRadius}" Content="{TemplateBinding Content}" ContentTransitions="{TemplateBinding ContentTransitions}" ContentTemplate="{TemplateBinding ContentTemplate}" Padding="{TemplateBinding Padding}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" AutomationProperties.AccessibilityView="Raw" />
|
||||
<ContentPresenter x:Name="ContentPresenter" IsRightTapEnabled="False" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" CornerRadius="{TemplateBinding CornerRadius}" Content="{TemplateBinding Content}" ContentTransitions="{TemplateBinding ContentTransitions}" ContentTemplate="{TemplateBinding ContentTemplate}" Padding="{TemplateBinding Padding}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" AutomationProperties.AccessibilityView="Raw" />
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="GridViewItem">
|
||||
<ListViewItemPresenter x:Name="Root" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<ListViewItemPresenter x:Name="Root" IsRightTapEnabled="False" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal"/>
|
||||
@@ -46,6 +46,7 @@
|
||||
<Grid
|
||||
x:Name="PowerBar"
|
||||
Background="{ThemeResource BackdropAcrylicBrush}"
|
||||
IsRightTapEnabled="False"
|
||||
VerticalAlignment="Top">
|
||||
|
||||
<ListView
|
||||
@@ -55,15 +56,18 @@
|
||||
MinHeight="{Binding Results.MaxHeight}"
|
||||
AllowFocusOnInteraction="False"
|
||||
IsItemClickEnabled="True"
|
||||
IsRightTapEnabled="False"
|
||||
RightTapped="SuggestionsList_RightTapped"
|
||||
Margin="0"
|
||||
Padding="{ThemeResource AutoSuggestListPadding}"
|
||||
ItemsSource="{Binding Results.Results, Mode=OneWay}"
|
||||
SelectionMode="Single"
|
||||
SelectedIndex="{Binding Results.SelectedIndex, Mode=TwoWay}"
|
||||
Style="{StaticResource ListViewNoAnimations}">
|
||||
Style="{StaticResource ListViewNoAnimations}"
|
||||
ItemContainerStyle="{StaticResource ListViewItemNoRightTap}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate >
|
||||
<Grid Height="72" Width="642" Background="Transparent" RowSpacing="0">
|
||||
<Grid IsRightTapEnabled ="False" Height="72" Width="642" Background="Transparent" RowSpacing="0">
|
||||
<Interactivity:Interaction.Behaviors>
|
||||
<Core:EventTriggerBehavior EventName="PointerEntered">
|
||||
<Core:InvokeCommandAction Command="{Binding ActivateContextButtonsHoverCommand}"/>
|
||||
@@ -81,9 +85,9 @@
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Image x:Name="AppIcon" Height="36" MaxWidth="56" Grid.RowSpan="2" Margin="-8,0,0,0" HorizontalAlignment="Center" Source="{Binding Image}" />
|
||||
<TextBlock x:Name="Title" Grid.Column="1" Text="{Binding Result.Title}" FontWeight="SemiBold" FontSize="20" Margin="0,0,0,-2" VerticalAlignment="Bottom"/>
|
||||
<TextBlock x:Name="Path" Grid.Column="1" Text= "{Binding Result.SubTitle}" Grid.Row="1" Opacity="0.6" Margin="0,2,0,0" VerticalAlignment="Top"/>
|
||||
<Image x:Name="AppIcon" IsRightTapEnabled ="False" Height="36" MaxWidth="56" Grid.RowSpan="2" Margin="-8,0,0,0" HorizontalAlignment="Center" Source="{Binding Image}" />
|
||||
<TextBlock x:Name="Title" IsRightTapEnabled ="False" Grid.Column="1" Text="{Binding Result.Title}" FontWeight="SemiBold" FontSize="20" Margin="0,0,0,-2" VerticalAlignment="Bottom"/>
|
||||
<TextBlock x:Name="Path" IsRightTapEnabled ="False" Grid.Column="1" Text= "{Binding Result.SubTitle}" Grid.Row="1" Opacity="0.6" Margin="0,2,0,0" VerticalAlignment="Top"/>
|
||||
<GridView
|
||||
ItemContainerStyle="{StaticResource CommandButtonGridViewItemContainerStyle}"
|
||||
HorizontalAlignment="Right"
|
||||
@@ -97,15 +101,17 @@
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
ItemsSource="{Binding ContextMenuItems}"
|
||||
SelectionMode="Single"
|
||||
SelectedIndex="{Binding ContextMenuSelectedIndex}">
|
||||
SelectedIndex="{Binding ContextMenuSelectedIndex}"
|
||||
ContainerContentChanging="GridView_ContainerContentChanging"
|
||||
IsRightTapEnabled ="False">
|
||||
<GridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button Command="{Binding Command}" VerticalAlignment="Center" CornerRadius="4" Height="42" Width="42" BorderThickness="1" Style="{ThemeResource IconOnlyButton}" Click="ContextButton_OnClick">
|
||||
<Button IsRightTapEnabled ="False" Command="{Binding Command}" VerticalAlignment="Center" CornerRadius="4" Height="42" Width="42" BorderThickness="1" Style="{ThemeResource IconOnlyButton}" Click="ContextButton_OnClick">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock Text="{Binding Title}"/>
|
||||
<TextBlock x:Name="ToolTip" Loaded="ToolTip_Loaded" IsRightTapEnabled="False" Text="{Binding Title}"/>
|
||||
</ToolTipService.ToolTip>
|
||||
<Button.Content>
|
||||
<FontIcon FontFamily="{Binding FontFamily}" FontSize="16" Glyph="{Binding Glyph}"/>
|
||||
<FontIcon x:Name="FontIcon" Loaded="FontIcon_Loaded" IsRightTapEnabled="False" FontFamily="{Binding FontFamily}" FontSize="16" Glyph="{Binding Glyph}"/>
|
||||
</Button.Content>
|
||||
<Button.KeyboardAccelerators>
|
||||
<KeyboardAccelerator
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
@@ -89,5 +91,74 @@ namespace PowerLauncher.UI
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
|
||||
private void SuggestionsList_RightTapped(object sender, Windows.UI.Xaml.Input.RightTappedRoutedEventArgs e)
|
||||
{
|
||||
Debug.WriteLine($"Right Tap was triggered on {e.OriginalSource}");
|
||||
}
|
||||
|
||||
private void FontIcon_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DisableRightClick(sender);
|
||||
}
|
||||
|
||||
private void ToolTip_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DisableRightClick(sender);
|
||||
}
|
||||
|
||||
|
||||
private void GridView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
|
||||
{
|
||||
DisableRightClick(sender);
|
||||
}
|
||||
|
||||
private void DisableRightClick(object o)
|
||||
{
|
||||
var element = o as UIElement;
|
||||
if (element != null)
|
||||
{
|
||||
DisableRightClick(element, isRecursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
public void DisableRightClick(UIElement element, bool isRecursive)
|
||||
{
|
||||
element.IsRightTapEnabled = false;
|
||||
|
||||
|
||||
if (isRecursive)
|
||||
{
|
||||
var children = FindChildren<UIElement>(element);
|
||||
foreach (var child in children)
|
||||
{
|
||||
child.IsRightTapEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<T> FindChildren<T>(DependencyObject startNode, List<T> results = null)
|
||||
where T : DependencyObject
|
||||
{
|
||||
if (results == null)
|
||||
{
|
||||
results = new List<T>();
|
||||
}
|
||||
|
||||
int count = VisualTreeHelper.GetChildrenCount(startNode);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
DependencyObject current = VisualTreeHelper.GetChild(startNode, i);
|
||||
if ((current.GetType()).Equals(typeof(T)) || (current.GetType().GetTypeInfo().IsSubclassOf(typeof(T))))
|
||||
{
|
||||
T asType = (T)current;
|
||||
results.Add(asType);
|
||||
}
|
||||
FindChildren<T>(current, results);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@ modular for additional plugins. Press Alt+Space and start typing!
|
||||

|
||||
|
||||
# 1\. Get Started
|
||||
## 1\.1 Features
|
||||
## 1\.1 Requirements
|
||||
|
||||
- Windows 10 version 1903 or higher
|
||||
|
||||
## 1\.2 Features
|
||||
Search for applications, folders, or files
|
||||

|
||||
|
||||
@@ -27,13 +31,13 @@ Do a simple calculation using calculator
|
||||
|
||||

|
||||
|
||||
## 1\.2 Settings
|
||||
## 1\.3 Settings
|
||||
| **Settings** | **Action** |
|
||||
| --------------- | ------------------------------------------------------------------------------- |
|
||||
| Maximum number of results | Maximum number of results shown without scrolling on PowerToys Run |
|
||||
| Open PowerToys Run shortcut | The keyboard shortcut to open/hide PowerToys Run |
|
||||
|
||||
## 1\.3 Keyboard Shortcuts
|
||||
## 1\.4 Keyboard Shortcuts
|
||||
| **Shortcuts** | **Action** |
|
||||
| ------------------ | ---------------------------------------------------------------------------------|
|
||||
| Alt+Space | Open or hide PowerToys Run |
|
||||
@@ -68,4 +72,4 @@ For a list of all known issues/suggestions, check it out
|
||||
|
||||
[Wox](https://github.com/Wox-launcher/Wox/)
|
||||
|
||||
[Beta Tadele's Window Walker](https://github.com/Wox-launcher/Wox/)
|
||||
[Beta Tadele's Window Walker](https://github.com/betsegaw/windowwalker)
|
||||
|
||||
@@ -83,9 +83,18 @@ namespace Wox.Infrastructure
|
||||
bool allSubstringsContainedInCompareString = true;
|
||||
|
||||
var indexList = new List<int>();
|
||||
List<int> spaceIndices = new List<int>();
|
||||
|
||||
for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++)
|
||||
{
|
||||
|
||||
// To maintain a list of indices which correspond to spaces in the string to compare
|
||||
// To populate the list only for the first query substring
|
||||
if (fullStringToCompareWithoutCase[compareStringIndex].Equals(' ') && currentQuerySubstringIndex == 0)
|
||||
{
|
||||
spaceIndices.Add(compareStringIndex);
|
||||
}
|
||||
|
||||
if (fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex])
|
||||
{
|
||||
matchFoundInPreviousLoop = false;
|
||||
@@ -147,7 +156,8 @@ namespace Wox.Infrastructure
|
||||
// proceed to calculate score if every char or substring without whitespaces matched
|
||||
if (allQuerySubstringsMatched)
|
||||
{
|
||||
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString);
|
||||
var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex);
|
||||
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString);
|
||||
|
||||
return new MatchResult(true, UserSettingSearchPrecision, indexList, score);
|
||||
}
|
||||
@@ -155,6 +165,21 @@ namespace Wox.Infrastructure
|
||||
return new MatchResult (false, UserSettingSearchPrecision);
|
||||
}
|
||||
|
||||
// To get the index of the closest space which preceeds the first matching index
|
||||
private int CalculateClosestSpaceIndex(List<int> spaceIndices, int firstMatchIndex)
|
||||
{
|
||||
if(spaceIndices.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int? ind = spaceIndices.OrderBy(item => (firstMatchIndex - item)).Where(item => firstMatchIndex > item).FirstOrDefault();
|
||||
int closestSpaceIndex = ind ?? -1;
|
||||
return closestSpaceIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQuerySubstringCharacterIndex,
|
||||
string fullStringToCompareWithoutCase, string currentQuerySubstring)
|
||||
{
|
||||
@@ -223,6 +248,12 @@ namespace Wox.Infrastructure
|
||||
}
|
||||
}
|
||||
|
||||
if (String.Equals(query, stringToCompare, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
var bonusForExactMatch = 10;
|
||||
score += bonusForExactMatch;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,21 +122,24 @@ namespace Wox.Test
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(Chrome, Chrome, 137)]
|
||||
[TestCase(Chrome, LastIsChrome, 83)]
|
||||
[TestCase(Chrome, HelpCureHopeRaiseOnMindEntityChrome, 21)]
|
||||
[TestCase(Chrome, UninstallOrChangeProgramsOnYourComputer, 15)]
|
||||
[TestCase(Chrome, CandyCrushSagaFromKing, 0)]
|
||||
[TestCase("sql", MicrosoftSqlServerManagementStudio, 56)]
|
||||
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, 79)]//double spacing intended
|
||||
public void WhenGivenQueryStringThenShouldReturnCurrentScoring(string queryString, string compareString, int expectedScore)
|
||||
[TestCase("vim", "Vim", "ignoreDescription", "ignore.exe", "Vim Diff", "ignoreDescription", "ignore.exe")]
|
||||
public void WhenMultipleResults_ExactMatchingResult_ShouldHaveGreatestScore(string queryString, string firstName, string firstDescription, string firstExecutableName, string secondName, string secondDescription, string secondExecutableName)
|
||||
{
|
||||
// When, Given
|
||||
// Act
|
||||
var matcher = new StringMatcher();
|
||||
var rawScore = matcher.FuzzyMatch(queryString, compareString).RawScore;
|
||||
var firstNameMatch = matcher.FuzzyMatch(queryString, firstName).RawScore;
|
||||
var firstDescriptionMatch = matcher.FuzzyMatch(queryString, firstDescription).RawScore;
|
||||
var firstExecutableNameMatch = matcher.FuzzyMatch(queryString, firstExecutableName).RawScore;
|
||||
|
||||
// Should
|
||||
Assert.AreEqual(expectedScore, rawScore, $"Expected score for compare string '{compareString}': {expectedScore}, Actual: {rawScore}");
|
||||
var secondNameMatch = matcher.FuzzyMatch(queryString, secondName).RawScore;
|
||||
var secondDescriptionMatch = matcher.FuzzyMatch(queryString, secondDescription).RawScore;
|
||||
var secondExecutableNameMatch = matcher.FuzzyMatch(queryString, secondExecutableName).RawScore;
|
||||
|
||||
var firstScore = new[] { firstNameMatch, firstDescriptionMatch, firstExecutableNameMatch }.Max();
|
||||
var secondScore = new[] { secondNameMatch, secondDescriptionMatch, secondExecutableNameMatch }.Max();
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(firstScore > secondScore);
|
||||
}
|
||||
|
||||
[TestCase("goo", "Google Chrome", StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
@@ -184,8 +187,6 @@ namespace Wox.Test
|
||||
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("sql", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("sql serv", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("sqlserv", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)]
|
||||
[TestCase("sql servman", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)]
|
||||
[TestCase("sql serv man", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("sql studio", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
[TestCase("mic", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)]
|
||||
@@ -221,5 +222,20 @@ namespace Wox.Test
|
||||
$"Raw Score: {matchResult.RawScore}{Environment.NewLine}" +
|
||||
$"Precision Score: {(int)expectedPrecisionScore}");
|
||||
}
|
||||
|
||||
[TestCase("Windows Terminal", "Windows_Terminal", "term")]
|
||||
[TestCase("Windows Terminal", "WindowsTerminal", "term")]
|
||||
public void FuzzyMatchingScore_ShouldBeHigher_WhenPreceedingCharacterIsSpace(string firstCompareStr, string secondCompareStr, string query)
|
||||
{
|
||||
// Arrange
|
||||
var matcher = new StringMatcher();
|
||||
|
||||
// Act
|
||||
var firstScore = matcher.FuzzyMatch(query, firstCompareStr).Score;
|
||||
var secondScore = matcher.FuzzyMatch(query, secondCompareStr).Score;
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(firstScore > secondScore);
|
||||
}
|
||||
}
|
||||
}
|
||||
143
src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs
Normal file
143
src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Wox.Infrastructure;
|
||||
using Wox.Plugin;
|
||||
using Microsoft.Plugin.Program.Programs;
|
||||
using Moq;
|
||||
using System.IO;
|
||||
|
||||
namespace Wox.Test.Plugins
|
||||
{
|
||||
[TestFixture]
|
||||
public class ProgramPluginTest
|
||||
{
|
||||
Win32 notepad_appdata = new Win32
|
||||
{
|
||||
Name = "Notepad",
|
||||
ExecutableName = "notepad.exe",
|
||||
FullPath = "c:\\windows\\system32\\notepad.exe",
|
||||
LnkResolvedPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\accessories\\notepad.lnk"
|
||||
};
|
||||
|
||||
Win32 notepad_users = new Win32
|
||||
{
|
||||
Name = "Notepad",
|
||||
ExecutableName = "notepad.exe",
|
||||
FullPath = "c:\\windows\\system32\\notepad.exe",
|
||||
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\accessories\\notepad.lnk"
|
||||
};
|
||||
|
||||
Win32 azure_command_prompt = new Win32
|
||||
{
|
||||
Name = "Microsoft Azure Command Prompt - v2.9",
|
||||
ExecutableName = "cmd.exe",
|
||||
FullPath = "c:\\windows\\system32\\cmd.exe",
|
||||
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\microsoft azure\\microsoft azure sdk for .net\\v2.9\\microsoft azure command prompt - v2.9.lnk"
|
||||
};
|
||||
|
||||
Win32 visual_studio_command_prompt = new Win32
|
||||
{
|
||||
Name = "x64 Native Tools Command Prompt for VS 2019",
|
||||
ExecutableName = "cmd.exe",
|
||||
FullPath = "c:\\windows\\system32\\cmd.exe",
|
||||
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\visual studio 2019\\visual studio tools\\vc\\x64 native tools command prompt for vs 2019.lnk"
|
||||
};
|
||||
|
||||
Win32 command_prompt = new Win32
|
||||
{
|
||||
Name = "Command Prompt",
|
||||
ExecutableName = "cmd.exe",
|
||||
FullPath = "c:\\windows\\system32\\cmd.exe",
|
||||
LnkResolvedPath ="c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\system tools\\command prompt.lnk"
|
||||
};
|
||||
|
||||
Win32 file_explorer = new Win32
|
||||
{
|
||||
Name = "File Explorer",
|
||||
ExecutableName = "File Explorer.lnk",
|
||||
FullPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\system tools\\file explorer.lnk",
|
||||
LnkResolvedPath = null
|
||||
};
|
||||
|
||||
Win32 wordpad = new Win32
|
||||
{
|
||||
Name = "Wordpad",
|
||||
ExecutableName = "wordpad.exe",
|
||||
FullPath = "c:\\program files\\windows nt\\accessories\\wordpad.exe",
|
||||
LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\accessories\\wordpad.lnk"
|
||||
};
|
||||
|
||||
Win32 wordpad_duplicate = new Win32
|
||||
{
|
||||
Name = "WORDPAD",
|
||||
ExecutableName = "WORDPAD.EXE",
|
||||
FullPath = "c:\\program files\\windows nt\\accessories\\wordpad.exe",
|
||||
LnkResolvedPath = null
|
||||
};
|
||||
|
||||
|
||||
[Test]
|
||||
public void DedupFunction_whenCalled_mustRemoveDuplicateNotepads()
|
||||
{
|
||||
// Arrange
|
||||
List<Win32> prgms = new List<Win32>();
|
||||
prgms.Add(notepad_appdata);
|
||||
prgms.Add(notepad_users);
|
||||
|
||||
// Act
|
||||
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(apps.Length, 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DedupFunction_whenCalled_mustNotRemovelnkWhichdoesNotHaveExe()
|
||||
{
|
||||
// Arrange
|
||||
List<Win32> prgms = new List<Win32>();
|
||||
prgms.Add(file_explorer);
|
||||
|
||||
// Act
|
||||
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(apps.Length, 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DedupFunction_mustRemoveDuplicates_forExeExtensionsWithoutLnkResolvedPath()
|
||||
{
|
||||
// Arrange
|
||||
List<Win32> prgms = new List<Win32>();
|
||||
prgms.Add(wordpad);
|
||||
prgms.Add(wordpad_duplicate);
|
||||
|
||||
// Act
|
||||
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(apps.Length, 1);
|
||||
Assert.IsTrue(!string.IsNullOrEmpty(apps[0].LnkResolvedPath));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DedupFunction_mustNotRemovePrograms_withSameExeNameAndFullPath()
|
||||
{
|
||||
// Arrange
|
||||
List<Win32> prgms = new List<Win32>();
|
||||
prgms.Add(azure_command_prompt);
|
||||
prgms.Add(visual_studio_command_prompt);
|
||||
prgms.Add(command_prompt);
|
||||
|
||||
// Act
|
||||
Win32[] apps = Win32.DeduplicatePrograms(prgms.AsParallel());
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(apps.Length, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Plugins\Microsoft.Plugin.Indexer\Microsoft.Plugin.Indexer.csproj" />
|
||||
<ProjectReference Include="..\Plugins\Microsoft.Plugin.Program\Microsoft.Plugin.Program.csproj" />
|
||||
<ProjectReference Include="..\Wox.Core\Wox.Core.csproj" />
|
||||
<ProjectReference Include="..\Wox.Infrastructure\Wox.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Wox.Plugin\Wox.Plugin.csproj" />
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace MarkdownPreviewHandler.Telemetry.Events
|
||||
/// <summary>
|
||||
/// Gets The version string. TODO: This should be replaced by a P/Invoke call to get_product_version.
|
||||
/// </summary>
|
||||
public string Version => "v0.18.0";
|
||||
public string Version => "v0.18.2";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace SvgPreviewHandler.Telemetry.Events
|
||||
/// <summary>
|
||||
/// Gets The version string. TODO: This should be replaced by a P/Invoke call to get_product_version.
|
||||
/// </summary>
|
||||
public string Version => "v0.18.0";
|
||||
public string Version => "v0.18.2";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
|
||||
@@ -36,7 +36,7 @@ bool restart_if_scheduled()
|
||||
case RestartAsElevated:
|
||||
return run_elevated(exe_path.get(), {});
|
||||
case RestartAsNonElevated:
|
||||
return run_non_elevated(exe_path.get(), L"--dont-elevate");
|
||||
return run_non_elevated(exe_path.get(), L"--dont-elevate", NULL);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -47,5 +47,5 @@ bool restart_same_elevation()
|
||||
constexpr DWORD exe_path_size = 0xFFFF;
|
||||
auto exe_path = std::make_unique<wchar_t[]>(exe_path_size);
|
||||
GetModuleFileNameW(nullptr, exe_path.get(), exe_path_size);
|
||||
return run_same_elevation(exe_path.get(), L"--dont-elevate");
|
||||
return run_same_elevation(exe_path.get(), L"--dont-elevate", nullptr);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user