mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-29 16:36:40 +01:00
Compare commits
24 Commits
yuleng/cmd
...
user/yeela
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0cafb99c6 | ||
|
|
d314fa075e | ||
|
|
90723d5b12 | ||
|
|
f2a5505601 | ||
|
|
311ab88ec3 | ||
|
|
c04400e7df | ||
|
|
05218e8af6 | ||
|
|
6cf73ce839 | ||
|
|
4f9e829155 | ||
|
|
397d5cf655 | ||
|
|
01584f33e1 | ||
|
|
67463abf98 | ||
|
|
e95a570d48 | ||
|
|
cb27874805 | ||
|
|
f65a3fc06f | ||
|
|
c7789abf04 | ||
|
|
e700f86ace | ||
|
|
a16f784011 | ||
|
|
4e0db267dc | ||
|
|
0e98cbd57e | ||
|
|
f15bed5323 | ||
|
|
d3c4e808d0 | ||
|
|
2b5181b4c9 | ||
|
|
60f50d853b |
1
.github/actions/spell-check/allow/names.txt
vendored
1
.github/actions/spell-check/allow/names.txt
vendored
@@ -189,6 +189,7 @@ Zoltan
|
||||
Zykova
|
||||
Sameerjs
|
||||
ruslanlap
|
||||
vednig
|
||||
|
||||
# OTHERS
|
||||
|
||||
|
||||
13
.github/actions/spell-check/expect.txt
vendored
13
.github/actions/spell-check/expect.txt
vendored
@@ -173,6 +173,7 @@ CContext
|
||||
CDeclaration
|
||||
CElems
|
||||
CENTERALIGN
|
||||
cer
|
||||
certlm
|
||||
certmgr
|
||||
cfp
|
||||
@@ -272,6 +273,7 @@ CURSORINFO
|
||||
cursorpos
|
||||
customaction
|
||||
CUSTOMACTIONTEST
|
||||
CUSTOMFORMATPLACEHOLDER
|
||||
CVal
|
||||
cvd
|
||||
CVirtual
|
||||
@@ -343,6 +345,7 @@ DEVMODE
|
||||
DEVMODEW
|
||||
devpal
|
||||
DIALOGEX
|
||||
digicert
|
||||
dimm
|
||||
DISABLEASACTIONKEY
|
||||
DISABLENOSCROLL
|
||||
@@ -678,6 +681,7 @@ IGo
|
||||
iid
|
||||
Iindex
|
||||
Ijwhost
|
||||
ILD
|
||||
IMAGEHLP
|
||||
IMAGERESIZERCONTEXTMENU
|
||||
IMAGERESIZEREXT
|
||||
@@ -938,6 +942,7 @@ mpmc
|
||||
MRM
|
||||
MRT
|
||||
mru
|
||||
MSAL
|
||||
msc
|
||||
mscorlib
|
||||
msctls
|
||||
@@ -1001,6 +1006,7 @@ netsh
|
||||
newcolor
|
||||
NEWDIALOGSTYLE
|
||||
NEWFILE
|
||||
NEWFILEHEADER
|
||||
newitem
|
||||
newpath
|
||||
newplus
|
||||
@@ -1295,6 +1301,7 @@ QUNS
|
||||
QXZ
|
||||
RAII
|
||||
RAlt
|
||||
Rappl
|
||||
randi
|
||||
Rasterization
|
||||
Rasterize
|
||||
@@ -1453,6 +1460,9 @@ SHELLDLL
|
||||
shellex
|
||||
SHELLEXECUTEINFO
|
||||
SHELLEXECUTEINFOW
|
||||
SHELLEXTENSION
|
||||
SHELLICONSIZE
|
||||
SHELLNEWVALUE
|
||||
SHFILEINFO
|
||||
SHFILEOPSTRUCT
|
||||
SHGDN
|
||||
@@ -1460,6 +1470,7 @@ SHGDNF
|
||||
SHGFI
|
||||
SHGFIICON
|
||||
SHGFILARGEICON
|
||||
SHIL
|
||||
shinfo
|
||||
shlwapi
|
||||
shobjidl
|
||||
@@ -1491,6 +1502,7 @@ SIDs
|
||||
siex
|
||||
sigdn
|
||||
SIGNINGSCENARIO
|
||||
signtool
|
||||
Signtool
|
||||
SINGLEKEY
|
||||
sipolicy
|
||||
@@ -1638,6 +1650,7 @@ telephon
|
||||
templatenamespace
|
||||
testprocess
|
||||
TEXCOORD
|
||||
TEXTBOXNEWLINE
|
||||
TEXTEXTRACTOR
|
||||
TEXTINCLUDE
|
||||
tfopen
|
||||
|
||||
26
.github/workflows/dependency-review.yml
vendored
Normal file
26
.github/workflows/dependency-review.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# Dependency Review Action
|
||||
#
|
||||
# This Action will scan dependency manifest files that change as part of a Pull Request,
|
||||
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
|
||||
# Once installed, if the workflow run is marked as required,
|
||||
# PRs introducing known-vulnerable packages will be blocked from merging.
|
||||
#
|
||||
# As recommended by Microsoft's security guidelines (https://docs.opensource.microsoft.com/security/tsg/actions/#requirements-for-security-hardening-your-own-github-actions),
|
||||
# 3rd-party actions should be pinned to a specific commit hash to prevent supply chain attacks.
|
||||
# This update aligns with best practices; 1st/2nd-party actions is not required hash pinning.
|
||||
#
|
||||
# Source repository: https://github.com/actions/dependency-review-action
|
||||
name: 'Dependency Review'
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@v4
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@v4
|
||||
8
.github/workflows/spelling2.yml
vendored
8
.github/workflows/spelling2.yml
vendored
@@ -93,7 +93,7 @@ jobs:
|
||||
steps:
|
||||
- name: check-spelling
|
||||
id: spelling
|
||||
uses: check-spelling/check-spelling@v0.0.24
|
||||
uses: check-spelling/check-spelling@67debf50669c7fc76fc8f5d7f996384535a72b77 # v0.0.24
|
||||
with:
|
||||
config: .github/actions/spell-check
|
||||
suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@v0.0.24
|
||||
uses: check-spelling/check-spelling@67debf50669c7fc76fc8f5d7f996384535a72b77 # v0.0.24
|
||||
with:
|
||||
config: .github/actions/spell-check
|
||||
checkout: true
|
||||
@@ -175,7 +175,7 @@ jobs:
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@v0.0.24
|
||||
uses: check-spelling/check-spelling@67debf50669c7fc76fc8f5d7f996384535a72b77 # v0.0.24
|
||||
with:
|
||||
config: .github/actions/spell-check
|
||||
checkout: true
|
||||
@@ -202,7 +202,7 @@ jobs:
|
||||
cancel-in-progress: false
|
||||
steps:
|
||||
- name: apply spelling updates
|
||||
uses: check-spelling/check-spelling@v0.0.24
|
||||
uses: check-spelling/check-spelling@67debf50669c7fc76fc8f5d7f996384535a72b77 # v0.0.24
|
||||
with:
|
||||
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
|
||||
checkout: true
|
||||
|
||||
@@ -220,6 +220,7 @@
|
||||
"WinUI3Apps\\PowerToys.Settings.exe",
|
||||
|
||||
"PowerToys.CmdPalModuleInterface.dll",
|
||||
"CmdPalKeyboardService.dll",
|
||||
"*Microsoft.CmdPal.UI_*.msix"
|
||||
],
|
||||
"SigningInfo": {
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
<PackageVersion Include="Azure.AI.OpenAI" Version="1.0.0-beta.17" />
|
||||
<PackageVersion Include="CommunityToolkit.Common" Version="8.4.0" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Animations" Version="8.2.250129-preview2" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Collections" Version="8.2.250129-preview2" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250129-preview2" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.2.250129-preview2" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.2.250129-preview2" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Sizers" Version="8.2.250129-preview2" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Converters" Version="8.2.250129-preview2" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250129-preview2" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Animations" Version="8.2.250402" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Collections" Version="8.2.250402" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250402" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.2.250402" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.2.250402" />
|
||||
<PackageVersion Include="CommunityToolkit.WinUI.Controls.Sizers" Version="8.2.250402" />
|
||||
<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.WinUI.UI.Controls.Markdown" Version="7.1.2" />
|
||||
<PackageVersion Include="ControlzEx" Version="6.0.0" />
|
||||
|
||||
50
NOTICE.md
50
NOTICE.md
@@ -75,6 +75,40 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
```
|
||||
|
||||
## Utility: Command Palette Built-in Extensions
|
||||
|
||||
### Calculator
|
||||
|
||||
#### Mages
|
||||
|
||||
We use the Mages NuGet package for calculating the result of expression.
|
||||
|
||||
**Source**: [https://github.com/FlorianRappl/Mages](https://github.com/FlorianRappl/Mages)
|
||||
|
||||
```
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 - 2025 Florian Rappl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
## Utility: File Explorer Add-ins
|
||||
|
||||
### Monaco Editor
|
||||
@@ -1400,14 +1434,14 @@ SOFTWARE.
|
||||
- Azure.AI.OpenAI 1.0.0-beta.17
|
||||
- CommunityToolkit.Common 8.4.0
|
||||
- CommunityToolkit.Mvvm 8.4.0
|
||||
- CommunityToolkit.WinUI.Animations 8.2.250129-preview2
|
||||
- CommunityToolkit.WinUI.Collections 8.2.250129-preview2
|
||||
- CommunityToolkit.WinUI.Controls.Primitives 8.2.250129-preview2
|
||||
- CommunityToolkit.WinUI.Controls.Segmented 8.2.250129-preview2
|
||||
- CommunityToolkit.WinUI.Controls.SettingsControls 8.2.250129-preview2
|
||||
- CommunityToolkit.WinUI.Controls.Sizers 8.2.250129-preview2
|
||||
- CommunityToolkit.WinUI.Converters 8.2.250129-preview2
|
||||
- CommunityToolkit.WinUI.Extensions 8.2.250129-preview2
|
||||
- CommunityToolkit.WinUI.Animations 8.2.250402
|
||||
- CommunityToolkit.WinUI.Collections 8.2.250402
|
||||
- CommunityToolkit.WinUI.Controls.Primitives 8.2.250402
|
||||
- CommunityToolkit.WinUI.Controls.Segmented 8.2.250402
|
||||
- CommunityToolkit.WinUI.Controls.SettingsControls 8.2.250402
|
||||
- CommunityToolkit.WinUI.Controls.Sizers 8.2.250402
|
||||
- CommunityToolkit.WinUI.Converters 8.2.250402
|
||||
- CommunityToolkit.WinUI.Extensions 8.2.250402
|
||||
- CommunityToolkit.WinUI.UI.Controls.DataGrid 7.1.2
|
||||
- CommunityToolkit.WinUI.UI.Controls.Markdown 7.1.2
|
||||
- ControlzEx 6.0.0
|
||||
|
||||
@@ -624,19 +624,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CommandPalette", "CommandPa
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Built-in Extensions", "Built-in Extensions", "{ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Apps", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj", "{6CE438DF-C245-4997-A360-0A0939E4BA34}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Apps", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj", "{6CE438DF-C245-4997-A360-0A0939E4BA34}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Bookmarks", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Bookmark\Microsoft.CmdPal.Ext.Bookmarks.csproj", "{E09AA983-C755-474F-83D6-A5CDF528C070}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Bookmarks", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Bookmark\Microsoft.CmdPal.Ext.Bookmarks.csproj", "{E09AA983-C755-474F-83D6-A5CDF528C070}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Calc", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Calc\Microsoft.CmdPal.Ext.Calc.csproj", "{6D56B64D-FF1F-488F-AFED-9B9854A5D399}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Calc", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Calc\Microsoft.CmdPal.Ext.Calc.csproj", "{6D56B64D-FF1F-488F-AFED-9B9854A5D399}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Registry", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Registry\Microsoft.CmdPal.Ext.Registry.csproj", "{92EC89E4-9972-453A-8A1A-3A9E230C146A}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Registry", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Registry\Microsoft.CmdPal.Ext.Registry.csproj", "{92EC89E4-9972-453A-8A1A-3A9E230C146A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsServices", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WindowsServices\Microsoft.CmdPal.Ext.WindowsServices.csproj", "{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsServices", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WindowsServices\Microsoft.CmdPal.Ext.WindowsServices.csproj", "{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsSettings", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WindowsSettings\Microsoft.CmdPal.Ext.WindowsSettings.csproj", "{D1160404-D3D1-497A-883A-4059C07C2273}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsSettings", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WindowsSettings\Microsoft.CmdPal.Ext.WindowsSettings.csproj", "{D1160404-D3D1-497A-883A-4059C07C2273}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsTerminal", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WindowsTerminal\Microsoft.CmdPal.Ext.WindowsTerminal.csproj", "{40F6D69D-E321-400F-A767-5628C7AE453D}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsTerminal", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WindowsTerminal\Microsoft.CmdPal.Ext.WindowsTerminal.csproj", "{40F6D69D-E321-400F-A767-5628C7AE453D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extension SDK", "Extension SDK", "{F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}"
|
||||
EndProject
|
||||
@@ -650,9 +650,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI", "sr
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sample Extensions", "Sample Extensions", "{071E18A4-A530-46B8-AB7D-B862EE55E24E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProcessMonitorExtension", "src\modules\cmdpal\Exts\ProcessMonitorExtension\ProcessMonitorExtension.csproj", "{C846F7A7-792A-47D9-B0CB-417C900EE03D}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProcessMonitorExtension", "src\modules\cmdpal\ext\ProcessMonitorExtension\ProcessMonitorExtension.csproj", "{C846F7A7-792A-47D9-B0CB-417C900EE03D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplePagesExtension", "src\modules\cmdpal\Exts\SamplePagesExtension\SamplePagesExtension.csproj", "{C831231F-891C-4572-9694-45062534B42A}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplePagesExtension", "src\modules\cmdpal\ext\SamplePagesExtension\SamplePagesExtension.csproj", "{C831231F-891C-4572-9694-45062534B42A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{7520A2FE-00A2-49B8-83ED-DB216E874C04}"
|
||||
EndProject
|
||||
@@ -660,7 +660,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.UI", "src\
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.UI.ViewModels", "src\modules\cmdpal\Microsoft.CmdPal.UI.ViewModels\Microsoft.CmdPal.UI.ViewModels.csproj", "{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.ClipboardHistory", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.ClipboardHistory\Microsoft.CmdPal.Ext.ClipboardHistory.csproj", "{79775343-7A3D-445D-9104-3DD5B2893DF9}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.ClipboardHistory", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.ClipboardHistory\Microsoft.CmdPal.Ext.ClipboardHistory.csproj", "{79775343-7A3D-445D-9104-3DD5B2893DF9}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalModuleInterface", "src\modules\cmdpal\CmdPalModuleInterface\CmdPalModuleInterface.vcxproj", "{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}"
|
||||
EndProject
|
||||
@@ -668,15 +668,15 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspacesCsharpLibrary", "
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewPlus.ShellExtension.win10", "src\modules\NewPlus\NewShellExtensionContextMenu.win10\NewPlus.ShellExtension.win10.vcxproj", "{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Indexer", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj", "{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Indexer", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj", "{453CBB73-A3CB-4D0B-8D24-6940B86FE21D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Shell", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.Shell\Microsoft.CmdPal.Ext.Shell.csproj", "{C0CE3B5E-16D3-495D-B335-CA791B660162}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Shell", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Shell\Microsoft.CmdPal.Ext.Shell.csproj", "{C0CE3B5E-16D3-495D-B335-CA791B660162}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowWalker", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WindowWalker\Microsoft.CmdPal.Ext.WindowWalker.csproj", "{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowWalker", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WindowWalker\Microsoft.CmdPal.Ext.WindowWalker.csproj", "{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSearch", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WebSearch\Microsoft.CmdPal.Ext.WebSearch.csproj", "{605E914B-7232-4789-AF46-BF5D3DDFC14E}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSearch", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WebSearch\Microsoft.CmdPal.Ext.WebSearch.csproj", "{605E914B-7232-4789-AF46-BF5D3DDFC14E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WinGet", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.WinGet\Microsoft.CmdPal.Ext.WinGet.csproj", "{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WinGet", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WinGet\Microsoft.CmdPal.Ext.WinGet.csproj", "{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.UnitTests", "src\modules\AdvancedPaste\AdvancedPaste.UnitTests\AdvancedPaste.UnitTests.csproj", "{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}"
|
||||
EndProject
|
||||
@@ -690,7 +690,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomItModuleInterface", "sr
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomItSettingsInterop", "src\modules\ZoomIt\ZoomItSettingsInterop\ZoomItSettingsInterop.vcxproj", "{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.TimeDate", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.TimeDate\Microsoft.CmdPal.Ext.TimeDate.csproj", "{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.TimeDate", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.TimeDate\Microsoft.CmdPal.Ext.TimeDate.csproj", "{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UITestAutomation", "src\common\UITestAutomation\UITestAutomation.csproj", "{A558C25D-2007-498E-8B6F-43405AFAE9E2}"
|
||||
EndProject
|
||||
@@ -704,7 +704,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hosts.UITests", "src\module
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegistryPreview.FuzzTests", "src\modules\registrypreview\RegistryPreview.FuzzTests\RegistryPreview.FuzzTests.csproj", "{5702B3CC-8575-48D5-83D8-15BB42269CD3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System", "src\modules\cmdpal\Exts\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj", "{64B88F02-CD88-4ED8-9624-989A800230F9}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj", "{64B88F02-CD88-4ED8-9624-989A800230F9}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalKeyboardService", "src\modules\cmdpal\CmdPalKeyboardService\CmdPalKeyboardService.vcxproj", "{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -2574,14 +2576,18 @@ Global
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x64.Build.0 = Debug|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x86.Build.0 = Debug|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.ActiveCfg = Release|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.Build.0 = Release|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x86.ActiveCfg = Release|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x86.Build.0 = Release|x64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|x64.Build.0 = Debug|x64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Release|x64.ActiveCfg = Release|x64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -2852,6 +2858,7 @@ Global
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
|
||||
{5702B3CC-8575-48D5-83D8-15BB42269CD3} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
||||
@@ -68,3 +68,4 @@ Below are community created plugins that target a website or software. They are
|
||||
| [Bilibili](https://github.com/Whuihuan/PowerToysRun-Bilibili) | [Whuihuan](https://github.com/Whuihuan) | Use AVID or BVID to parse and jump to Bilibili |
|
||||
| [YubicoOauthOTP](https://github.com/dlnilsson/Community.PowerToys.Run.Plugin.YubicoOauthOTP) | [dlnilsson](https://github.com/dlnilsson) | Display generated codes from OATH accounts stored on the YubiKey in powerToys Run |
|
||||
| [Firefox Bookmark](https://github.com/8LWXpg/PowerToysRun-FirefoxBookmark) | [8LWXpg](https://github.com/8LWXpg) | Open bookmarks in Firefox based browser |
|
||||
[Linear](https://github.com/vednig/powertoys-linear) | [vednig](https://github.com/vednig) | Create Linear Issues directly from Powertoys Run |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
@@ -63,8 +63,16 @@ using System.Diagnostics.CodeAnalysis;
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "<Dotnet port with style preservation>", Scope = "namespaceanddescendants", Target = "MouseWithoutBorders")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "<Dotnet port with style preservation>", Scope = "namespaceanddescendants", Target = "MouseWithoutBorders")]
|
||||
|
||||
// AOT
|
||||
// AOT MVVMTK0045
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "AdvancedPaste.ViewModels")]
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "HostsUILib")]
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "EnvironmentVariablesUILib")]
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "Peek.FilePreviewer")]
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "Peek.UI")]
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "Peek.UI.Views")]
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0045:Using [ObservableProperty] on fields is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "RegistryPreviewUILib")]
|
||||
|
||||
// AOT MVVMTK0049
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0049:Using [INotifyPropertyChanged] is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "Peek.FilePreviewer")]
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "MVVMTK0049:Using [INotifyPropertyChanged] is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "type", Target = "~T:Peek.UI.Views.TitleBar")]
|
||||
[assembly: SuppressMessage("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "MVVMTK0049:Using [INotifyPropertyChanged] is not AOT compatible for WinRT", Justification = "Updated MVVM toolkit package introduced this.", Scope = "namespaceanddescendants", Target = "RegistryPreviewUILib")]
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
EXPORTS
|
||||
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
|
||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", FILE_DESCRIPTION
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", INTERNAL_NAME
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
||||
@@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
|
||||
<CppWinRTGenerateWindowsMetadata>true</CppWinRTGenerateWindowsMetadata>
|
||||
<ProjectGuid>{5f63c743-f6ce-4dba-a200-2b3f8a14e8c2}</ProjectGuid>
|
||||
<ProjectName>CmdPalKeyboardService</ProjectName>
|
||||
<RootNamespace>CmdPalKeyboardService</RootNamespace>
|
||||
<AppxPackage>false</AppxPackage>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- BEGIN common.build.pre.props -->
|
||||
<PropertyGroup Label="Configuration">
|
||||
<EnableHybridCRT>true</EnableHybridCRT>
|
||||
<UseCrtSDKReferenceStaticWarning Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReferenceStaticWarning>
|
||||
</PropertyGroup>
|
||||
<!-- END common.build.pre.props -->
|
||||
<!-- BEGIN cppwinrt.build.pre.props -->
|
||||
<PropertyGroup Label="Globals">
|
||||
<CppWinRTEnabled>true</CppWinRTEnabled>
|
||||
<CppWinRTOptimized>true</CppWinRTOptimized>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<MinimumVisualStudioVersion>17.0</MinimumVisualStudioVersion>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<MinimalCoreWin>true</MinimalCoreWin>
|
||||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<WindowsStoreApp>true</WindowsStoreApp>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<UseCrtSDKReference Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReference> <!-- The SDK reference breaks the Hybrid CRT -->
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<!-- We have to use the Desktop platform for Hybrid CRT to work. -->
|
||||
<_VC_Target_Library_Platform>Desktop</_VC_Target_Library_Platform>
|
||||
<_NoWinAPIFamilyApp>true</_NoWinAPIFamilyApp>
|
||||
</PropertyGroup>
|
||||
<!-- END cppwinrt.build.pre.props -->
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="PropertySheet.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<TargetName>CmdPalKeyboardService</TargetName>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
|
||||
<PreprocessorDefinitions>_WINRT_DLL;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
<ModuleDefinitionFile>CmdPalKeyboardService.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>Shell32.lib;user32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="KeyboardListener.h">
|
||||
<DependentUpon>KeyboardListener.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyboardListener.cpp">
|
||||
<DependentUpon>KeyboardListener.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="KeyboardListener.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="CmdPalKeyboardService.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="PropertySheet.props" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="CmdPalKeyboardService.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
|
||||
<!-- BEGIN common.build.post.props -->
|
||||
<!--
|
||||
The Hybrid CRT model statically links the runtime and STL and dynamically
|
||||
links the UCRT instead of the VC++ CRT. The UCRT ships with Windows.
|
||||
WinAppSDK asserts that this is "supported according to the CRT maintainer."
|
||||
|
||||
This must come before Microsoft.Cpp.targets because it manipulates ClCompile.RuntimeLibrary.
|
||||
-->
|
||||
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and '$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and ('$(Configuration)'=='Release' or '$(Configuration)'=='AuditMode')">
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<!-- END common.build.post.props -->
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Resources">
|
||||
<UniqueIdentifier>accd3aa8-1ba0-4223-9bbe-0c431709210b</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{926ab91d-31b4-48c3-b9a4-e681349f27f0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="KeyboardListener.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CmdPalKeyboardService.def" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="PropertySheet.props" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="CmdPalKeyboardService.rc">
|
||||
<Filter>Resources</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
165
src/modules/cmdpal/CmdPalKeyboardService/KeyboardListener.cpp
Normal file
165
src/modules/cmdpal/CmdPalKeyboardService/KeyboardListener.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#include "pch.h"
|
||||
#include "KeyboardListener.h"
|
||||
#include "KeyboardListener.g.cpp"
|
||||
|
||||
// #include <common/logger/logger.h>
|
||||
// #include <common/utils/logger_helper.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
}
|
||||
|
||||
namespace winrt::CmdPalKeyboardService::implementation
|
||||
{
|
||||
KeyboardListener::KeyboardListener()
|
||||
{
|
||||
s_instance = this;
|
||||
}
|
||||
|
||||
void KeyboardListener::Start()
|
||||
{
|
||||
#if defined(DISABLE_LOWLEVEL_HOOKS_WHEN_DEBUGGED)
|
||||
const bool hook_disabled = IsDebuggerPresent();
|
||||
#else
|
||||
const bool hook_disabled = false;
|
||||
#endif
|
||||
if (!hook_disabled)
|
||||
{
|
||||
if (!s_llKeyboardHook)
|
||||
{
|
||||
s_llKeyboardHook = SetWindowsHookExW(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, NULL);
|
||||
if (!s_llKeyboardHook)
|
||||
{
|
||||
DWORD errorCode = GetLastError();
|
||||
show_last_error_message(L"SetWindowsHookEx", errorCode, L"CmdPalKeyboardService");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::Stop()
|
||||
{
|
||||
if (s_llKeyboardHook && UnhookWindowsHookEx(s_llKeyboardHook))
|
||||
{
|
||||
s_llKeyboardHook = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::SetHotkeyAction(bool win, bool ctrl, bool shift, bool alt, uint8_t key, hstring const& id)
|
||||
{
|
||||
Hotkey hotkey = { .win = win, .ctrl = ctrl, .shift = shift, .alt = alt, .key = key };
|
||||
std::unique_lock lock{ mutex };
|
||||
|
||||
HotkeyDescriptor desc = { .hotkey = hotkey, .id = std::wstring(id) };
|
||||
hotkeyDescriptors.insert(desc);
|
||||
}
|
||||
|
||||
void KeyboardListener::ClearHotkey(hstring const& id)
|
||||
{
|
||||
{
|
||||
std::unique_lock lock{ mutex };
|
||||
auto it = hotkeyDescriptors.begin();
|
||||
while (it != hotkeyDescriptors.end())
|
||||
{
|
||||
if (it->id == id)
|
||||
{
|
||||
it = hotkeyDescriptors.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::ClearHotkeys()
|
||||
{
|
||||
{
|
||||
std::unique_lock lock{ mutex };
|
||||
auto it = hotkeyDescriptors.begin();
|
||||
while (it != hotkeyDescriptors.end())
|
||||
{
|
||||
it = hotkeyDescriptors.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::SetProcessCommand(ProcessCommand processCommand)
|
||||
{
|
||||
m_processCommandCb = [trigger = std::move(processCommand)](hstring const& id) {
|
||||
trigger(id);
|
||||
};
|
||||
}
|
||||
|
||||
LRESULT KeyboardListener::DoLowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
const auto& keyPressInfo = *reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||
|
||||
if ((wParam != WM_KEYDOWN) && (wParam != WM_SYSKEYDOWN))
|
||||
{
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
Hotkey hotkey{
|
||||
.win = (GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000),
|
||||
.ctrl = static_cast<bool>(GetAsyncKeyState(VK_CONTROL) & 0x8000),
|
||||
.shift = static_cast<bool>(GetAsyncKeyState(VK_SHIFT) & 0x8000),
|
||||
.alt = static_cast<bool>(GetAsyncKeyState(VK_MENU) & 0x8000),
|
||||
.key = static_cast<unsigned char>(keyPressInfo.vkCode)
|
||||
};
|
||||
|
||||
if (hotkey == Hotkey{})
|
||||
{
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
bool do_action = false;
|
||||
std::wstring actionId{};
|
||||
|
||||
{
|
||||
// Hold the lock for the shortest possible duration
|
||||
std::unique_lock lock{ mutex };
|
||||
HotkeyDescriptor dummy{ .hotkey = hotkey };
|
||||
auto it = hotkeyDescriptors.find(dummy);
|
||||
if (it != hotkeyDescriptors.end())
|
||||
{
|
||||
do_action = true;
|
||||
actionId = it->id;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_action)
|
||||
{
|
||||
m_processCommandCb(hstring{ actionId });
|
||||
|
||||
// After invoking the hotkey send a dummy key to prevent Start Menu from activating
|
||||
INPUT dummyEvent[1] = {};
|
||||
dummyEvent[0].type = INPUT_KEYBOARD;
|
||||
dummyEvent[0].ki.wVk = 0xFF;
|
||||
dummyEvent[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
SendInput(1, dummyEvent, sizeof(INPUT));
|
||||
|
||||
// Swallow the key press
|
||||
return 1;
|
||||
}
|
||||
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT KeyboardListener::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (s_instance == nullptr)
|
||||
{
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
if (nCode < 0)
|
||||
{
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
return s_instance->DoLowLevelKeyboardProc(nCode, wParam, lParam);
|
||||
}
|
||||
}
|
||||
67
src/modules/cmdpal/CmdPalKeyboardService/KeyboardListener.h
Normal file
67
src/modules/cmdpal/CmdPalKeyboardService/KeyboardListener.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include "KeyboardListener.g.h"
|
||||
#include <mutex>
|
||||
#include <spdlog/stopwatch.h>
|
||||
#include <set>
|
||||
|
||||
namespace winrt::CmdPalKeyboardService::implementation
|
||||
{
|
||||
struct KeyboardListener : KeyboardListenerT<KeyboardListener>
|
||||
{
|
||||
struct Hotkey
|
||||
{
|
||||
bool win = false;
|
||||
bool ctrl = false;
|
||||
bool shift = false;
|
||||
bool alt = false;
|
||||
unsigned char key = 0;
|
||||
|
||||
std::strong_ordering operator<=>(const Hotkey&) const = default;
|
||||
};
|
||||
|
||||
struct HotkeyDescriptor
|
||||
{
|
||||
Hotkey hotkey;
|
||||
std::wstring id;
|
||||
|
||||
bool operator<(const HotkeyDescriptor& other) const
|
||||
{
|
||||
return hotkey < other.hotkey;
|
||||
};
|
||||
};
|
||||
|
||||
KeyboardListener();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
void SetHotkeyAction(bool win, bool ctrl, bool shift, bool alt, uint8_t key, hstring const& id);
|
||||
void ClearHotkey(hstring const& id);
|
||||
void ClearHotkeys();
|
||||
void SetProcessCommand(ProcessCommand processCommand);
|
||||
|
||||
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
LRESULT CALLBACK DoLowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
static inline KeyboardListener* s_instance;
|
||||
HHOOK s_llKeyboardHook = nullptr;
|
||||
|
||||
// Max DWORD for key code to disable keys.
|
||||
const DWORD VK_DISABLED = 0x100;
|
||||
DWORD vkCodePressed = VK_DISABLED;
|
||||
|
||||
std::multiset<HotkeyDescriptor> hotkeyDescriptors;
|
||||
std::mutex mutex;
|
||||
|
||||
std::function<void(hstring const&)> m_processCommandCb;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::CmdPalKeyboardService::factory_implementation
|
||||
{
|
||||
struct KeyboardListener : KeyboardListenerT<KeyboardListener, implementation::KeyboardListener>
|
||||
{
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
namespace CmdPalKeyboardService
|
||||
{
|
||||
[version(1.0), uuid(78ab07cd-e128-4e73-86aa-e48e6b6d01ff)] delegate void ProcessCommand(String id);
|
||||
|
||||
[default_interface] runtimeclass KeyboardListener {
|
||||
KeyboardListener();
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
void SetHotkeyAction(Boolean win, Boolean ctrl, Boolean shift, Boolean alt, UInt8 key, String id);
|
||||
void ClearHotkey(String id);
|
||||
void ClearHotkeys();
|
||||
void SetProcessCommand(ProcessCommand processCommand);
|
||||
}
|
||||
}
|
||||
17
src/modules/cmdpal/CmdPalKeyboardService/PropertySheet.props
Normal file
17
src/modules/cmdpal/CmdPalKeyboardService/PropertySheet.props
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<!--
|
||||
To customize common C++/WinRT project properties:
|
||||
* right-click the project node
|
||||
* expand the Common Properties item
|
||||
* select the C++/WinRT property page
|
||||
|
||||
For more advanced scenarios, and complete documentation, please see:
|
||||
https://github.com/Microsoft/cppwinrt/tree/master/nuget
|
||||
-->
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup />
|
||||
</Project>
|
||||
4
src/modules/cmdpal/CmdPalKeyboardService/packages.config
Normal file
4
src/modules/cmdpal/CmdPalKeyboardService/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
</packages>
|
||||
1
src/modules/cmdpal/CmdPalKeyboardService/pch.cpp
Normal file
1
src/modules/cmdpal/CmdPalKeyboardService/pch.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
4
src/modules/cmdpal/CmdPalKeyboardService/pch.h
Normal file
4
src/modules/cmdpal/CmdPalKeyboardService/pch.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <Unknwn.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
13
src/modules/cmdpal/CmdPalKeyboardService/resource.h
Normal file
13
src/modules/cmdpal/CmdPalKeyboardService/resource.h
Normal file
@@ -0,0 +1,13 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by PowerToys.MeasureToolCore.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "CmdPalKeyboardService"
|
||||
#define INTERNAL_NAME "CmdPalKeyboardService"
|
||||
#define ORIGINAL_FILENAME "CmdPalKeyboardService.dll"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
||||
@@ -207,12 +207,16 @@ public:
|
||||
|
||||
try
|
||||
{
|
||||
if (!package::GetRegisteredPackage(L"Microsoft.CommandPalette", false).has_value())
|
||||
std::wstring packageName = L"Microsoft.CommandPalette";
|
||||
#ifdef _DEBUG
|
||||
packageName = L"Microsoft.CommandPalette.Dev";
|
||||
#endif
|
||||
if (!package::GetRegisteredPackage(packageName, false).has_value())
|
||||
{
|
||||
Logger::info(L"CmdPal not installed. Installing...");
|
||||
|
||||
std::wstring installationFolder = get_module_folderpath();
|
||||
#if _DEBUG
|
||||
#ifdef _DEBUG
|
||||
std::wstring archSubdir = L"x64";
|
||||
#ifdef _M_ARM64
|
||||
archSubdir = L"ARM64";
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Microsoft.CmdPal.Ext.Calc.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Calc;
|
||||
|
||||
public partial class CalculatorCommandProvider : CommandProvider
|
||||
{
|
||||
private readonly ListItem _listItem = new(new CalculatorListPage()) { Subtitle = Resources.calculator_top_level_subtitle };
|
||||
private readonly FallbackCalculatorItem _fallback = new();
|
||||
|
||||
public CalculatorCommandProvider()
|
||||
{
|
||||
Id = "Calculator";
|
||||
DisplayName = Resources.calculator_display_name;
|
||||
Icon = IconHelpers.FromRelativePath("Assets\\Calculator.svg");
|
||||
}
|
||||
|
||||
public override ICommandItem[] TopLevelCommands() => [_listItem];
|
||||
|
||||
public override IFallbackCommandItem[] FallbackCommands() => [_fallback];
|
||||
}
|
||||
|
||||
// The calculator page is a dynamic list page
|
||||
// * The first command is where we display the results. Title=result, Subtitle=query
|
||||
// - The default command is `SaveCommand`.
|
||||
// - When you save, insert into list at spot 1
|
||||
// - change SearchText to the result
|
||||
// - MoreCommands: a single `CopyCommand` to copy the result to the clipboard
|
||||
// * The rest of the items are previously saved results
|
||||
// - Command is a CopyCommand
|
||||
// - Each item also sets the TextToSuggest to the result
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "This is sample code")]
|
||||
public sealed partial class CalculatorListPage : DynamicListPage
|
||||
{
|
||||
private readonly List<ListItem> _items = [];
|
||||
private readonly SaveCommand _saveCommand = new();
|
||||
private readonly CopyTextCommand _copyContextCommand;
|
||||
private readonly CommandContextItem _copyContextMenuItem;
|
||||
private static readonly CompositeFormat ErrorMessage = System.Text.CompositeFormat.Parse(Properties.Resources.calculator_error);
|
||||
|
||||
public CalculatorListPage()
|
||||
{
|
||||
Icon = IconHelpers.FromRelativePath("Assets\\Calculator.svg");
|
||||
Name = Resources.calculator_title;
|
||||
PlaceholderText = Resources.calculator_placeholder_text;
|
||||
Id = "com.microsoft.cmdpal.calculator";
|
||||
|
||||
_copyContextCommand = new CopyTextCommand(string.Empty);
|
||||
_copyContextMenuItem = new CommandContextItem(_copyContextCommand);
|
||||
|
||||
_items.Add(new(_saveCommand) { Icon = new IconInfo("\uE94E") });
|
||||
|
||||
UpdateSearchText(string.Empty, string.Empty);
|
||||
|
||||
_saveCommand.SaveRequested += HandleSave;
|
||||
}
|
||||
|
||||
private void HandleSave(object sender, object args)
|
||||
{
|
||||
var lastResult = _items[0].Title;
|
||||
if (!string.IsNullOrEmpty(lastResult))
|
||||
{
|
||||
var li = new ListItem(new CopyTextCommand(lastResult))
|
||||
{
|
||||
Title = _items[0].Title,
|
||||
Subtitle = _items[0].Subtitle,
|
||||
TextToSuggest = lastResult,
|
||||
};
|
||||
_items.Insert(1, li);
|
||||
_items[0].Subtitle = string.Empty;
|
||||
SearchText = lastResult;
|
||||
this.RaiseItemsChanged(this._items.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateSearchText(string oldSearch, string newSearch)
|
||||
{
|
||||
var firstItem = _items[0];
|
||||
if (string.IsNullOrEmpty(newSearch))
|
||||
{
|
||||
firstItem.Title = Resources.calculator_placeholder_text;
|
||||
firstItem.Subtitle = string.Empty;
|
||||
firstItem.MoreCommands = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
_copyContextCommand.Text = ParseQuery(newSearch, out var result) ? result : string.Empty;
|
||||
firstItem.Title = result;
|
||||
firstItem.Subtitle = newSearch;
|
||||
firstItem.MoreCommands = [_copyContextMenuItem];
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool ParseQuery(string equation, out string result)
|
||||
{
|
||||
try
|
||||
{
|
||||
var resultNumber = new DataTable().Compute(equation, null);
|
||||
result = resultNumber.ToString() ?? string.Empty;
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result = string.Format(CultureInfo.CurrentCulture, ErrorMessage, e.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override IListItem[] GetItems() => _items.ToArray();
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "This is sample code")]
|
||||
public sealed partial class SaveCommand : InvokableCommand
|
||||
{
|
||||
public event TypedEventHandler<object, object> SaveRequested;
|
||||
|
||||
public SaveCommand()
|
||||
{
|
||||
Name = Resources.calculator_save_command_name;
|
||||
}
|
||||
|
||||
public override ICommandResult Invoke()
|
||||
{
|
||||
SaveRequested?.Invoke(this, this);
|
||||
return CommandResult.KeepOpen();
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "This is sample code")]
|
||||
internal sealed partial class FallbackCalculatorItem : FallbackCommandItem
|
||||
{
|
||||
private readonly CopyTextCommand _copyCommand = new(string.Empty);
|
||||
private static readonly IconInfo _cachedIcon = IconHelpers.FromRelativePath("Assets\\Calculator.svg");
|
||||
|
||||
public FallbackCalculatorItem()
|
||||
: base(new NoOpCommand(), Resources.calculator_title)
|
||||
{
|
||||
Command = _copyCommand;
|
||||
_copyCommand.Name = string.Empty;
|
||||
Title = string.Empty;
|
||||
Subtitle = Resources.calculator_placeholder_text;
|
||||
Icon = _cachedIcon;
|
||||
}
|
||||
|
||||
public override void UpdateQuery(string query)
|
||||
{
|
||||
if (CalculatorListPage.ParseQuery(query, out var result))
|
||||
{
|
||||
_copyCommand.Text = result;
|
||||
_copyCommand.Name = string.IsNullOrWhiteSpace(query) ? string.Empty : Resources.calculator_copy_command_name;
|
||||
Title = result;
|
||||
|
||||
// we have to make the subtitle the equation,
|
||||
// so that we will still string match the original query
|
||||
// Otherwise, something like 1+2 will have a title of "3" and not match
|
||||
Subtitle = query;
|
||||
}
|
||||
else
|
||||
{
|
||||
_copyCommand.Text = string.Empty;
|
||||
_copyCommand.Name = string.Empty;
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.System.Helpers;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.System;
|
||||
|
||||
public sealed partial class SystemCommandsCache
|
||||
{
|
||||
public SystemCommandsCache(SettingsManager manager)
|
||||
{
|
||||
var list = new List<IListItem>();
|
||||
var listLock = new object();
|
||||
|
||||
var a = Task.Run(() =>
|
||||
{
|
||||
var isBootedInUefiMode = Win32Helpers.GetSystemFirmwareType() == FirmwareType.Uefi;
|
||||
|
||||
var separateEmptyRB = manager.HideEmptyRecycleBin;
|
||||
var confirmSystemCommands = manager.ShowDialogToConfirmCommand;
|
||||
var showSuccessOnEmptyRB = manager.ShowSuccessMessageAfterEmptyingRecycleBin;
|
||||
|
||||
// normal system commands are fast and can be returned immediately
|
||||
var systemCommands = Commands.GetSystemCommands(isBootedInUefiMode, separateEmptyRB, confirmSystemCommands, showSuccessOnEmptyRB);
|
||||
lock (listLock)
|
||||
{
|
||||
list.AddRange(systemCommands);
|
||||
}
|
||||
});
|
||||
|
||||
var b = Task.Run(() =>
|
||||
{
|
||||
// Network (ip and mac) results are slow with many network cards and returned delayed.
|
||||
// On global queries the first word/part has to be 'ip', 'mac' or 'address' for network results
|
||||
var networkConnectionResults = Commands.GetNetworkConnectionResults(manager);
|
||||
lock (listLock)
|
||||
{
|
||||
list.AddRange(networkConnectionResults);
|
||||
}
|
||||
});
|
||||
|
||||
Task.WaitAll(a, b);
|
||||
CachedCommands = list.ToArray();
|
||||
}
|
||||
|
||||
public IListItem[] CachedCommands { get; }
|
||||
}
|
||||
@@ -1,189 +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.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.TimeDate.Helpers;
|
||||
|
||||
internal static class TimeAndDateHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the format for the time string
|
||||
/// </summary>
|
||||
/// <param name="targetFormat">Type of format</param>
|
||||
/// <param name="timeLong">Show date with weekday and name of month (long format)</param>
|
||||
/// <param name="dateLong">Show time with seconds (long format)</param>
|
||||
/// <returns>String that identifies the time/date format (<see href="https://learn.microsoft.com/dotnet/api/system.datetime.tostring"/>)</returns>
|
||||
internal static string GetStringFormat(FormatStringType targetFormat, bool timeLong, bool dateLong)
|
||||
{
|
||||
switch (targetFormat)
|
||||
{
|
||||
case FormatStringType.Time:
|
||||
return timeLong ? "T" : "t";
|
||||
case FormatStringType.Date:
|
||||
return dateLong ? "D" : "d";
|
||||
case FormatStringType.DateTime:
|
||||
if (timeLong & dateLong)
|
||||
{
|
||||
return "F"; // Friday, October 31, 2008 5:04:32 PM
|
||||
}
|
||||
else if (timeLong & !dateLong)
|
||||
{
|
||||
return "G"; // 10/31/2008 5:04:32 PM
|
||||
}
|
||||
else if (!timeLong & dateLong)
|
||||
{
|
||||
return "f"; // Friday, October 31, 2008 5:04 PM
|
||||
}
|
||||
else
|
||||
{
|
||||
// (!timeLong & !dateLong)
|
||||
return "g"; // 10/31/2008 5:04 PM
|
||||
}
|
||||
|
||||
default:
|
||||
return string.Empty; // Windows default based on current culture settings
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number week in the month (Used code from 'David Morton' from <see href="https://social.msdn.microsoft.com/Forums/vstudio/bf504bba-85cb-492d-a8f7-4ccabdf882cb/get-week-number-for-month"/>)
|
||||
/// </summary>
|
||||
/// <param name="date">date</param>
|
||||
/// <returns>Number of week in the month</returns>
|
||||
internal static int GetWeekOfMonth(DateTime date, DayOfWeek formatSettingFirstDayOfWeek)
|
||||
{
|
||||
var beginningOfMonth = new DateTime(date.Year, date.Month, 1);
|
||||
var adjustment = 1; // We count from 1 to 7 and not from 0 to 6
|
||||
|
||||
while (date.Date.AddDays(1).DayOfWeek != formatSettingFirstDayOfWeek)
|
||||
{
|
||||
date = date.AddDays(1);
|
||||
}
|
||||
|
||||
return (int)Math.Truncate((double)date.Subtract(beginningOfMonth).TotalDays / 7f) + adjustment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of the day in the week
|
||||
/// </summary>
|
||||
/// <param name="date">Date</param>
|
||||
/// <returns>Number of the day in the week</returns>
|
||||
internal static int GetNumberOfDayInWeek(DateTime date, DayOfWeek formatSettingFirstDayOfWeek)
|
||||
{
|
||||
var daysInWeek = 7;
|
||||
var adjustment = 1; // We count from 1 to 7 and not from 0 to 6
|
||||
|
||||
return ((date.DayOfWeek + daysInWeek - formatSettingFirstDayOfWeek) % daysInWeek) + adjustment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert input string to a <see cref="DateTime"/> object in local time
|
||||
/// </summary>
|
||||
/// <param name="input">String with date/time</param>
|
||||
/// <param name="timestamp">The new <see cref="DateTime"/> object</param>
|
||||
/// <returns>True on success, otherwise false</returns>
|
||||
internal static bool ParseStringAsDateTime(in string input, out DateTime timestamp)
|
||||
{
|
||||
if (DateTime.TryParse(input, out timestamp))
|
||||
{
|
||||
// Known date/time format
|
||||
return true;
|
||||
}
|
||||
else if (Regex.IsMatch(input, @"^u[\+-]?\d{1,10}$") && long.TryParse(input.TrimStart('u'), out var secondsU))
|
||||
{
|
||||
// Unix time stamp
|
||||
// We use long instead of int, because int is too small after 03:14:07 UTC 2038-01-19
|
||||
timestamp = DateTimeOffset.FromUnixTimeSeconds(secondsU).LocalDateTime;
|
||||
return true;
|
||||
}
|
||||
else if (Regex.IsMatch(input, @"^ums[\+-]?\d{1,13}$") && long.TryParse(input.TrimStart("ums".ToCharArray()), out var millisecondsUms))
|
||||
{
|
||||
// Unix time stamp in milliseconds
|
||||
// We use long instead of int because int is too small after 03:14:07 UTC 2038-01-19
|
||||
timestamp = DateTimeOffset.FromUnixTimeMilliseconds(millisecondsUms).LocalDateTime;
|
||||
return true;
|
||||
}
|
||||
else if (Regex.IsMatch(input, @"^ft\d+$") && long.TryParse(input.TrimStart("ft".ToCharArray()), out var secondsFt))
|
||||
{
|
||||
// Windows file time
|
||||
// DateTime.FromFileTime returns as local time.
|
||||
timestamp = DateTime.FromFileTime(secondsFt);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
timestamp = new DateTime(1, 1, 1, 1, 1, 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if input is special parsing for Unix time, Unix time in milliseconds or File time.
|
||||
/// </summary>
|
||||
/// <param name="input">String with date/time</param>
|
||||
/// <returns>True if yes, otherwise false</returns>
|
||||
internal static bool IsSpecialInputParsing(string input)
|
||||
{
|
||||
return Regex.IsMatch(input, @"^.*(u|ums|ft)\d");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a CalendarWeekRule enum value based on the plugin setting.
|
||||
/// </summary>
|
||||
internal static CalendarWeekRule GetCalendarWeekRule(int pluginSetting)
|
||||
{
|
||||
switch (pluginSetting)
|
||||
{
|
||||
case 0:
|
||||
return CalendarWeekRule.FirstDay;
|
||||
case 1:
|
||||
return CalendarWeekRule.FirstFullWeek;
|
||||
case 2:
|
||||
return CalendarWeekRule.FirstFourDayWeek;
|
||||
default:
|
||||
// Wrong json value and system setting (-1).
|
||||
return DateTimeFormatInfo.CurrentInfo.CalendarWeekRule;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a DayOfWeek enum value based on the FirstDayOfWeek plugin setting.
|
||||
/// </summary>
|
||||
internal static DayOfWeek GetFirstDayOfWeek(int pluginSetting)
|
||||
{
|
||||
switch (pluginSetting)
|
||||
{
|
||||
case 0:
|
||||
return DayOfWeek.Sunday;
|
||||
case 1:
|
||||
return DayOfWeek.Monday;
|
||||
case 2:
|
||||
return DayOfWeek.Tuesday;
|
||||
case 3:
|
||||
return DayOfWeek.Wednesday;
|
||||
case 4:
|
||||
return DayOfWeek.Thursday;
|
||||
case 5:
|
||||
return DayOfWeek.Friday;
|
||||
case 6:
|
||||
return DayOfWeek.Saturday;
|
||||
default:
|
||||
// Wrong json value and system setting (-1).
|
||||
return DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of time/date format
|
||||
/// </summary>
|
||||
internal enum FormatStringType
|
||||
{
|
||||
Time,
|
||||
Date,
|
||||
DateTime,
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace SamplePagesExtension;
|
||||
|
||||
internal sealed partial class SampleListPage : ListPage
|
||||
{
|
||||
public SampleListPage()
|
||||
{
|
||||
Icon = new IconInfo("\uEA37");
|
||||
Name = "Sample List Page";
|
||||
}
|
||||
|
||||
public override IListItem[] GetItems()
|
||||
{
|
||||
var confirmOnceArgs = new ConfirmationArgs
|
||||
{
|
||||
PrimaryCommand = new AnonymousCommand(
|
||||
() =>
|
||||
{
|
||||
var t = new ToastStatusMessage("The dialog was confirmed");
|
||||
t.Show();
|
||||
})
|
||||
{
|
||||
Name = "Confirm",
|
||||
Result = CommandResult.KeepOpen(),
|
||||
},
|
||||
Title = "You can set a title for the dialog",
|
||||
Description = "Are you really sure you want to do the thing?",
|
||||
};
|
||||
var confirmTwiceArgs = new ConfirmationArgs
|
||||
{
|
||||
PrimaryCommand = new AnonymousCommand(() => { })
|
||||
{
|
||||
Name = "How sure are you?",
|
||||
Result = CommandResult.Confirm(confirmOnceArgs),
|
||||
},
|
||||
Title = "You can ask twice too",
|
||||
Description = "You probably don't want to though, that'd be annoying.",
|
||||
};
|
||||
|
||||
return [
|
||||
new ListItem(new NoOpCommand())
|
||||
{
|
||||
Title = "This is a basic item in the list",
|
||||
Subtitle = "I don't do anything though",
|
||||
},
|
||||
new ListItem(new SampleListPageWithDetails())
|
||||
{
|
||||
Title = "This item will take you to another page",
|
||||
Subtitle = "This allows for nested lists of items",
|
||||
},
|
||||
new ListItem(new OpenUrlCommand("https://github.com/microsoft/powertoys"))
|
||||
{
|
||||
Title = "Or you can go to links",
|
||||
Subtitle = "This takes you to the PowerToys repo on GitHub",
|
||||
},
|
||||
new ListItem(new SampleMarkdownPage())
|
||||
{
|
||||
Title = "Items can have tags",
|
||||
Subtitle = "and I'll take you to a page with markdown content",
|
||||
Tags = [new Tag("Sample Tag")],
|
||||
},
|
||||
new ListItem(new SendMessageCommand())
|
||||
{
|
||||
Title = "I send lots of messages",
|
||||
Subtitle = "Status messages can be used to provide feedback to the user in-app",
|
||||
},
|
||||
new SendSingleMessageItem(),
|
||||
new ListItem(new IndeterminateProgressMessageCommand())
|
||||
{
|
||||
Title = "Do a thing with a spinner",
|
||||
Subtitle = "Messages can have progress spinners, to indicate something is happening in the background",
|
||||
},
|
||||
new ListItem(
|
||||
new AnonymousCommand(() => { })
|
||||
{
|
||||
Result = CommandResult.Confirm(confirmOnceArgs),
|
||||
})
|
||||
{
|
||||
Title = "Confirm before doing something",
|
||||
},
|
||||
new ListItem(
|
||||
new AnonymousCommand(() => { })
|
||||
{
|
||||
Result = CommandResult.Confirm(confirmTwiceArgs),
|
||||
})
|
||||
{
|
||||
Title = "Confirm twice before doing something",
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,15 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.System;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
|
||||
public partial class CommandBarViewModel : ObservableObject,
|
||||
IRecipient<UpdateCommandBarMessage>
|
||||
IRecipient<UpdateCommandBarMessage>,
|
||||
IRecipient<UpdateItemKeybindingsMessage>
|
||||
{
|
||||
public ICommandBarContext? SelectedItem
|
||||
{
|
||||
@@ -49,13 +53,18 @@ public partial class CommandBarViewModel : ObservableObject,
|
||||
[ObservableProperty]
|
||||
public partial ObservableCollection<CommandContextItemViewModel> ContextCommands { get; set; } = [];
|
||||
|
||||
private Dictionary<KeyChord, CommandContextItemViewModel>? _contextKeybindings;
|
||||
|
||||
public CommandBarViewModel()
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<UpdateItemKeybindingsMessage>(this);
|
||||
}
|
||||
|
||||
public void Receive(UpdateCommandBarMessage message) => SelectedItem = message.ViewModel;
|
||||
|
||||
public void Receive(UpdateItemKeybindingsMessage message) => _contextKeybindings = message.Keys;
|
||||
|
||||
private void SetSelectedItem(ICommandBarContext? value)
|
||||
{
|
||||
if (value != null)
|
||||
@@ -131,4 +140,22 @@ public partial class CommandBarViewModel : ObservableObject,
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(SecondaryCommand.Command.Model, SecondaryCommand.Model));
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckKeybinding(bool ctrl, bool alt, bool shift, bool win, VirtualKey key)
|
||||
{
|
||||
if (_contextKeybindings != null)
|
||||
{
|
||||
// Does the pressed key match any of the keybindings?
|
||||
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrl, alt, shift, win, key, 0);
|
||||
if (_contextKeybindings.TryGetValue(pressedKeyChord, out var item))
|
||||
{
|
||||
// TODO GH #245: This is a bit of a hack, but we need to make sure that the keybindings are updated before we send the message
|
||||
// so that the correct item is activated.
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(item));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,16 @@ namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
|
||||
public partial class CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference<IPageContext> context) : CommandItemViewModel(new(contextItem), context)
|
||||
{
|
||||
private readonly KeyChord nullKeyChord = new(0, 0, 0);
|
||||
|
||||
public new ExtensionObject<ICommandContextItem> Model { get; } = new(contextItem);
|
||||
|
||||
public bool IsCritical { get; private set; }
|
||||
|
||||
public KeyChord? RequestedShortcut { get; private set; }
|
||||
|
||||
public bool HasRequestedShortcut => RequestedShortcut != null && (RequestedShortcut.Value != nullKeyChord);
|
||||
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
if (IsInitialized)
|
||||
@@ -31,6 +35,9 @@ public partial class CommandContextItemViewModel(ICommandContextItem contextItem
|
||||
}
|
||||
|
||||
IsCritical = contextItem.IsCritical;
|
||||
|
||||
// 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(
|
||||
|
||||
@@ -398,6 +398,23 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
base.SafeCleanup();
|
||||
Initialized |= InitializedState.CleanedUp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a mapping of key -> command item for this particular item's
|
||||
/// MoreCommands. (This won't include the primary Command, but it will
|
||||
/// include the secondary one). This map can be used to quickly check if a
|
||||
/// shortcut key was pressed
|
||||
/// </summary>
|
||||
/// <returns>a dictionary of KeyChord -> Context commands, for all commands
|
||||
/// that have a shortcut key set.</returns>
|
||||
internal Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
|
||||
{
|
||||
return MoreCommands
|
||||
.Where(c => c.HasRequestedShortcut)
|
||||
.ToDictionary(
|
||||
c => c.RequestedShortcut ?? new KeyChord(0, 0, 0),
|
||||
c => c);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.IO.Compression;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -28,69 +29,69 @@ internal sealed partial class NewExtensionForm : NewExtensionFormBase
|
||||
"body": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "{{Properties.Resources.builtin_create_extension_page_title}}",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_page_title)}},
|
||||
"size": "large"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "{{Properties.Resources.builtin_create_extension_page_text}}",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_page_text)}},
|
||||
"wrap": true
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "{{Properties.Resources.builtin_create_extension_name_header}}",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_name_header)}},
|
||||
"weight": "bolder",
|
||||
"size": "default"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "{{Properties.Resources.builtin_create_extension_name_description}}",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_name_description)}},
|
||||
"wrap": true
|
||||
},
|
||||
{
|
||||
"type": "Input.Text",
|
||||
"label": "{{Properties.Resources.builtin_create_extension_name_label}}",
|
||||
"label": {{FormatJsonString(Properties.Resources.builtin_create_extension_name_label)}},
|
||||
"isRequired": true,
|
||||
"errorMessage": "{{Properties.Resources.builtin_create_extension_name_required}}",
|
||||
"errorMessage": {{FormatJsonString(Properties.Resources.builtin_create_extension_name_required)}},
|
||||
"id": "ExtensionName",
|
||||
"placeholder": "ExtensionName",
|
||||
"regex": "^[^\\s]+$"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "{{Properties.Resources.builtin_create_extension_display_name_header}}",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_display_name_header)}},
|
||||
"weight": "bolder",
|
||||
"size": "default"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "{{Properties.Resources.builtin_create_extension_display_name_description}}",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_display_name_description)}},
|
||||
"wrap": true
|
||||
},
|
||||
{
|
||||
"type": "Input.Text",
|
||||
"label": "{{Properties.Resources.builtin_create_extension_display_name_label}}",
|
||||
"label": {{FormatJsonString(Properties.Resources.builtin_create_extension_display_name_label)}},
|
||||
"isRequired": true,
|
||||
"errorMessage": "{{Properties.Resources.builtin_create_extension_display_name_required}}",
|
||||
"errorMessage": {{FormatJsonString(Properties.Resources.builtin_create_extension_display_name_required)}},
|
||||
"id": "DisplayName",
|
||||
"placeholder": "My new extension"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "{{Properties.Resources.builtin_create_extension_directory_header}}",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_directory_header)}},
|
||||
"weight": "bolder",
|
||||
"size": "default"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "{{Properties.Resources.builtin_create_extension_directory_description}}",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_directory_description)}},
|
||||
"wrap": true
|
||||
},
|
||||
{
|
||||
"type": "Input.Text",
|
||||
"label": "{{Properties.Resources.builtin_create_extension_directory_label}}",
|
||||
"label": {{FormatJsonString(Properties.Resources.builtin_create_extension_directory_label)}},
|
||||
"isRequired": true,
|
||||
"errorMessage": "{{Properties.Resources.builtin_create_extension_directory_required}}",
|
||||
"errorMessage": {{FormatJsonString(Properties.Resources.builtin_create_extension_directory_required)}},
|
||||
"id": "OutputPath",
|
||||
"placeholder": "C:\\users\\me\\dev"
|
||||
}
|
||||
@@ -98,7 +99,7 @@ internal sealed partial class NewExtensionForm : NewExtensionFormBase
|
||||
"actions": [
|
||||
{
|
||||
"type": "Action.Submit",
|
||||
"title": "{{Properties.Resources.builtin_create_extension_submit}}",
|
||||
"title": {{FormatJsonString(Properties.Resources.builtin_create_extension_submit)}},
|
||||
"associatedInputs": "auto"
|
||||
}
|
||||
]
|
||||
@@ -192,4 +193,10 @@ internal sealed partial class NewExtensionForm : NewExtensionFormBase
|
||||
// Delete the temp dir
|
||||
Directory.Delete(tempDir, true);
|
||||
}
|
||||
|
||||
private string FormatJsonString(string str)
|
||||
{
|
||||
// Escape the string for JSON
|
||||
return JsonSerializer.Serialize(str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
|
||||
public string SearchText { get; private set; } = string.Empty;
|
||||
|
||||
public string InitialSearchText { get; private set; } = string.Empty;
|
||||
|
||||
public CommandItemViewModel EmptyContent { get; private set; }
|
||||
|
||||
private bool _isDynamic;
|
||||
@@ -128,7 +130,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
|
||||
try
|
||||
{
|
||||
IListItem[] newItems = _model.Unsafe!.GetItems();
|
||||
var newItems = _model.Unsafe!.GetItems();
|
||||
|
||||
// Collect all the items into new viewmodels
|
||||
Collection<ListItemViewModel> newViewModels = [];
|
||||
@@ -136,7 +138,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
// TODO we can probably further optimize this by also keeping a
|
||||
// HashSet of every ExtensionObject we currently have, and only
|
||||
// building new viewmodels for the ones we haven't already built.
|
||||
foreach (IListItem? item in newItems)
|
||||
foreach (var item in newItems)
|
||||
{
|
||||
ListItemViewModel viewModel = new(item, new(this));
|
||||
|
||||
@@ -147,8 +149,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<ListItemViewModel> firstTwenty = newViewModels.Take(20);
|
||||
foreach (ListItemViewModel? item in firstTwenty)
|
||||
var firstTwenty = newViewModels.Take(20);
|
||||
foreach (var item in firstTwenty)
|
||||
{
|
||||
item?.SafeInitializeProperties();
|
||||
}
|
||||
@@ -233,7 +235,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
iterable = Items.ToArray();
|
||||
}
|
||||
|
||||
foreach (ListItemViewModel item in iterable)
|
||||
foreach (var item in iterable)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -266,8 +268,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
return 1;
|
||||
}
|
||||
|
||||
MatchResult nameMatch = StringMatcher.FuzzySearch(query, listItem.Title);
|
||||
MatchResult descriptionMatch = StringMatcher.FuzzySearch(query, listItem.Subtitle);
|
||||
var nameMatch = StringMatcher.FuzzySearch(query, listItem.Title);
|
||||
var descriptionMatch = StringMatcher.FuzzySearch(query, listItem.Subtitle);
|
||||
return new[] { nameMatch.Score, (descriptionMatch.Score - 4) / 2, 0 }.Max();
|
||||
}
|
||||
|
||||
@@ -280,7 +282,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
// Similarly stolen from ListHelpers.FilterList
|
||||
public static IEnumerable<ListItemViewModel> FilterList(IEnumerable<ListItemViewModel> items, string query)
|
||||
{
|
||||
IOrderedEnumerable<ScoredListItemViewModel> scores = items
|
||||
var scores = items
|
||||
.Where(i => !i.IsInErrorState)
|
||||
.Select(li => new ScoredListItemViewModel() { ViewModel = li, Score = ScoreListItem(query, li) })
|
||||
.Where(score => score.Score > 0)
|
||||
@@ -342,6 +344,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(item));
|
||||
|
||||
WeakReferenceMessenger.Default.Send<UpdateItemKeybindingsMessage>(new(item.Keybindings()));
|
||||
|
||||
if (ShowDetails && item.HasDetails)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<ShowDetailsMessage>(new(item.Details));
|
||||
@@ -359,7 +363,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
{
|
||||
base.InitializeProperties();
|
||||
|
||||
IListPage? model = _model.Unsafe;
|
||||
var model = _model.Unsafe;
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
@@ -373,8 +377,9 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
_modelPlaceholderText = model.PlaceholderText;
|
||||
UpdateProperty(nameof(PlaceholderText));
|
||||
|
||||
SearchText = model.SearchText;
|
||||
InitialSearchText = SearchText = model.SearchText;
|
||||
UpdateProperty(nameof(SearchText));
|
||||
UpdateProperty(nameof(InitialSearchText));
|
||||
|
||||
EmptyContent = new(new(model.EmptyContent), PageContext);
|
||||
EmptyContent.SlowInitializeProperties();
|
||||
@@ -385,7 +390,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
|
||||
public void LoadMoreIfNeeded()
|
||||
{
|
||||
IListPage? model = this._model.Unsafe;
|
||||
var model = this._model.Unsafe;
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
@@ -412,7 +417,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
{
|
||||
base.FetchProperty(propertyName);
|
||||
|
||||
IListPage? model = this._model.Unsafe;
|
||||
var model = this._model.Unsafe;
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
@@ -475,13 +480,13 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
|
||||
lock (_listLock)
|
||||
{
|
||||
foreach (ListItemViewModel item in Items)
|
||||
foreach (var item in Items)
|
||||
{
|
||||
item.SafeCleanup();
|
||||
}
|
||||
|
||||
Items.Clear();
|
||||
foreach (ListItemViewModel item in FilteredItems)
|
||||
foreach (var item in FilteredItems)
|
||||
{
|
||||
item.SafeCleanup();
|
||||
}
|
||||
@@ -489,7 +494,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
FilteredItems.Clear();
|
||||
}
|
||||
|
||||
IListPage? model = _model.Unsafe;
|
||||
var model = _model.Unsafe;
|
||||
if (model != null)
|
||||
{
|
||||
model.ItemsChanged -= Model_ItemsChanged;
|
||||
|
||||
@@ -51,6 +51,12 @@ public record PerformCommandMessage
|
||||
Context = context.Unsafe;
|
||||
}
|
||||
|
||||
public PerformCommandMessage(CommandContextItemViewModel contextCommand)
|
||||
{
|
||||
Command = contextCommand.Command.Model;
|
||||
Context = contextCommand.Model.Unsafe;
|
||||
}
|
||||
|
||||
public PerformCommandMessage(ConfirmResultViewModel vm)
|
||||
{
|
||||
Command = vm.PrimaryCommand.Model;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
|
||||
public record UpdateItemKeybindingsMessage(Dictionary<KeyChord, CommandContextItemViewModel>? Keys);
|
||||
@@ -31,7 +31,7 @@
|
||||
<ProjectReference Include="..\Microsoft.CmdPal.Common\Microsoft.CmdPal.Common.csproj" />
|
||||
<ProjectReference Include="..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj" />
|
||||
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ public partial class SettingsModel : ObservableObject
|
||||
|
||||
public HotkeySettings? Hotkey { get; set; } = DefaultActivationShortcut;
|
||||
|
||||
public bool UseLowLevelGlobalHotkey { get; set; }
|
||||
|
||||
public bool ShowAppDetails { get; set; }
|
||||
|
||||
public bool HotkeyGoesHome { get; set; }
|
||||
|
||||
@@ -27,6 +27,17 @@ public partial class SettingsViewModel : INotifyPropertyChanged
|
||||
}
|
||||
}
|
||||
|
||||
public bool UseLowLevelGlobalHotkey
|
||||
{
|
||||
get => _settings.UseLowLevelGlobalHotkey;
|
||||
set
|
||||
{
|
||||
_settings.UseLowLevelGlobalHotkey = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Hotkey)));
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowAppDetails
|
||||
{
|
||||
get => _settings.ShowAppDetails;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<!-- Template for actions in the mode actions dropdown button -->
|
||||
<DataTemplate x:Key="ContextMenuViewModelTemplate" x:DataType="viewmodels:CommandContextItemViewModel">
|
||||
<Grid>
|
||||
<Grid AutomationProperties.Name="{x:Bind Title, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="32" />
|
||||
<ColumnDefinition Width="*" />
|
||||
@@ -53,37 +53,16 @@
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Title, Mode=OneWay}" />
|
||||
<!--<TextBlock
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
Margin="16,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{ThemeResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />-->
|
||||
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<animations:ImplicitAnimationSet x:Name="ShowAnimations">
|
||||
<animations:OpacityAnimation
|
||||
From="0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.340" />
|
||||
<animations:ScaleAnimation
|
||||
From="0.85"
|
||||
To="1"
|
||||
Duration="0:0:0.350" />
|
||||
</animations:ImplicitAnimationSet>
|
||||
<animations:ImplicitAnimationSet x:Name="HideAnimations">
|
||||
<animations:OpacityAnimation
|
||||
From="1.0"
|
||||
To="0"
|
||||
Duration="0:0:0.240" />
|
||||
<animations:ScaleAnimation
|
||||
From="1"
|
||||
To="0.85"
|
||||
Duration="0:0:0.350" />
|
||||
</animations:ImplicitAnimationSet>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
@@ -135,9 +114,6 @@
|
||||
<Button
|
||||
x:Name="SettingsIconButton"
|
||||
x:Uid="SettingsButton"
|
||||
animations:Implicit.HideAnimations="{StaticResource HideAnimations}"
|
||||
animations:Implicit.ShowAnimations="{StaticResource ShowAnimations}"
|
||||
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
|
||||
Style="{StaticResource SubtleButtonStyle}"
|
||||
Tapped="SettingsIcon_Tapped"
|
||||
Visibility="{x:Bind CurrentPageViewModel.IsNested, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
|
||||
@@ -167,10 +143,8 @@
|
||||
<Button
|
||||
x:Name="PrimaryButton"
|
||||
Padding="6,4,4,4"
|
||||
animations:Implicit.HideAnimations="{StaticResource HideAnimations}"
|
||||
animations:Implicit.ShowAnimations="{StaticResource ShowAnimations}"
|
||||
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
AutomationProperties.Name="{x:Bind ViewModel.PrimaryCommand.Name, Mode=OneWay}"
|
||||
Background="Transparent"
|
||||
Style="{StaticResource SubtleButtonStyle}"
|
||||
Tapped="PrimaryButton_Tapped"
|
||||
@@ -198,10 +172,8 @@
|
||||
<Button
|
||||
x:Name="SecondaryButton"
|
||||
Padding="6,4,4,4"
|
||||
animations:Implicit.HideAnimations="{StaticResource HideAnimations}"
|
||||
animations:Implicit.ShowAnimations="{StaticResource ShowAnimations}"
|
||||
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
AutomationProperties.Name="{x:Bind ViewModel.SecondaryCommand.Name, Mode=OneWay}"
|
||||
Style="{StaticResource SubtleButtonStyle}"
|
||||
Tapped="SecondaryButton_Tapped"
|
||||
Visibility="{x:Bind ViewModel.HasSecondaryCommand, Mode=OneWay}">
|
||||
@@ -245,13 +217,10 @@
|
||||
x:Name="MoreCommandsButton"
|
||||
x:Uid="MoreCommandsButton"
|
||||
Padding="4"
|
||||
animations:Implicit.HideAnimations="{StaticResource HideAnimations}"
|
||||
animations:Implicit.ShowAnimations="{StaticResource ShowAnimations}"
|
||||
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
|
||||
Content="{ui:FontIcon Glyph=,
|
||||
FontSize=16}"
|
||||
Style="{StaticResource SubtleButtonStyle}"
|
||||
ToolTipService.ToolTip="Ctrl+k"
|
||||
ToolTipService.ToolTip="Ctrl+K"
|
||||
Visibility="{x:Bind ViewModel.ShouldShowContextMenu, Mode=OneWay}">
|
||||
<Button.Flyout>
|
||||
<Flyout Placement="TopEdgeAlignedRight">
|
||||
@@ -263,6 +232,7 @@
|
||||
ItemClick="CommandsDropdown_ItemClick"
|
||||
ItemTemplate="{StaticResource ContextMenuViewModelTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.ContextCommands, Mode=OneWay}"
|
||||
KeyDown="CommandsDropdown_KeyDown"
|
||||
SelectionMode="None">
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style BasedOn="{StaticResource DefaultListViewItemStyle}" TargetType="ListViewItem">
|
||||
|
||||
@@ -6,10 +6,13 @@ using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.Views;
|
||||
using Microsoft.UI.Input;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Windows.System;
|
||||
using Windows.UI.Core;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Controls;
|
||||
|
||||
@@ -89,4 +92,23 @@ public sealed partial class CommandBar : UserControl,
|
||||
MoreCommandsButton.Flyout.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void CommandsDropdown_KeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
if (e.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
|
||||
var altPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down);
|
||||
var shiftPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
|
||||
var winPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.LeftWindows).HasFlag(CoreVirtualKeyStates.Down) ||
|
||||
InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.RightWindows).HasFlag(CoreVirtualKeyStates.Down);
|
||||
|
||||
if (ViewModel?.CheckKeybinding(ctrlPressed, altPressed, shiftPressed, winPressed, e.Key) ?? false)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ using CommunityToolkit.WinUI;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.Views;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Input;
|
||||
using Microsoft.UI.Xaml;
|
||||
@@ -21,6 +23,7 @@ namespace Microsoft.CmdPal.UI.Controls;
|
||||
public sealed partial class SearchBar : UserControl,
|
||||
IRecipient<GoHomeMessage>,
|
||||
IRecipient<FocusSearchBoxMessage>,
|
||||
IRecipient<UpdateItemKeybindingsMessage>,
|
||||
ICurrentPageAware
|
||||
{
|
||||
private readonly DispatcherQueue _queue = DispatcherQueue.GetForCurrentThread();
|
||||
@@ -31,6 +34,8 @@ public sealed partial class SearchBar : UserControl,
|
||||
private readonly DispatcherQueueTimer _debounceTimer = DispatcherQueue.GetForCurrentThread().CreateTimer();
|
||||
private bool _isBackspaceHeld;
|
||||
|
||||
private Dictionary<KeyChord, CommandContextItemViewModel>? _keyBindings;
|
||||
|
||||
public PageViewModel? CurrentPageViewModel
|
||||
{
|
||||
get => (PageViewModel?)GetValue(CurrentPageViewModelProperty);
|
||||
@@ -69,6 +74,7 @@ public sealed partial class SearchBar : UserControl,
|
||||
this.InitializeComponent();
|
||||
WeakReferenceMessenger.Default.Register<GoHomeMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<FocusSearchBoxMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<UpdateItemKeybindingsMessage>(this);
|
||||
}
|
||||
|
||||
public void ClearSearch()
|
||||
@@ -105,7 +111,9 @@ public sealed partial class SearchBar : UserControl,
|
||||
|
||||
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
|
||||
var altPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down);
|
||||
|
||||
var shiftPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
|
||||
var winPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.LeftWindows).HasFlag(CoreVirtualKeyStates.Down) ||
|
||||
InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.RightWindows).HasFlag(CoreVirtualKeyStates.Down);
|
||||
if (ctrlPressed && e.Key == VirtualKey.Enter)
|
||||
{
|
||||
// ctrl+enter
|
||||
@@ -164,6 +172,19 @@ public sealed partial class SearchBar : UserControl,
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<NavigateBackMessage>(new());
|
||||
}
|
||||
|
||||
if (_keyBindings != null)
|
||||
{
|
||||
// Does the pressed key match any of the keybindings?
|
||||
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrlPressed, altPressed, shiftPressed, winPressed, (int)e.Key, 0);
|
||||
if (_keyBindings.TryGetValue(pressedKeyChord, out var item))
|
||||
{
|
||||
// TODO GH #245: This is a bit of a hack, but we need to make sure that the keybindings are updated before we send the message
|
||||
// so that the correct item is activated.
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(item));
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FilterBox_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
||||
@@ -250,18 +271,31 @@ public sealed partial class SearchBar : UserControl,
|
||||
private void Page_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
var property = e.PropertyName;
|
||||
if (CurrentPageViewModel is ListViewModel list &&
|
||||
property == nameof(ListViewModel.SearchText))
|
||||
{
|
||||
// Only if the text actually changed...
|
||||
// (sometimes this triggers on a round-trip of the SearchText)
|
||||
if (FilterBox.Text != list.SearchText)
|
||||
{
|
||||
// ... Update our displayed text, and...
|
||||
FilterBox.Text = list.SearchText;
|
||||
|
||||
// ... Move the cursor to the end of the input
|
||||
FilterBox.Select(FilterBox.Text.Length, 0);
|
||||
if (CurrentPageViewModel is ListViewModel list)
|
||||
{
|
||||
if (property == nameof(ListViewModel.SearchText))
|
||||
{
|
||||
// Only if the text actually changed...
|
||||
// (sometimes this triggers on a round-trip of the SearchText)
|
||||
if (FilterBox.Text != list.SearchText)
|
||||
{
|
||||
// ... Update our displayed text, and...
|
||||
FilterBox.Text = list.SearchText;
|
||||
|
||||
// ... Move the cursor to the end of the input
|
||||
FilterBox.Select(FilterBox.Text.Length, 0);
|
||||
}
|
||||
}
|
||||
else if (property == nameof(ListViewModel.InitialSearchText))
|
||||
{
|
||||
// GH #38712:
|
||||
// The ListPage will notify us of the `InitialSearchText` when
|
||||
// we first load the viewmodel. We can use that as an
|
||||
// opportunity to immediately select the search text. That lets
|
||||
// the user start typing a new search without manually
|
||||
// selecting the old one.
|
||||
SelectSearch();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,4 +303,9 @@ public sealed partial class SearchBar : UserControl,
|
||||
public void Receive(GoHomeMessage message) => ClearSearch();
|
||||
|
||||
public void Receive(FocusSearchBoxMessage message) => this.Focus(Microsoft.UI.Xaml.FocusState.Programmatic);
|
||||
|
||||
public void Receive(UpdateItemKeybindingsMessage message)
|
||||
{
|
||||
_keyBindings = message.Keys;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="AutomationProperties.AutomationControlType" Value="Custom" />
|
||||
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
|
||||
<Setter Property="Padding" Value="{ThemeResource TagPadding}" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
@@ -56,6 +57,7 @@
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
||||
AutomationProperties.Name="{TemplateBinding Text}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
|
||||
@@ -28,21 +28,22 @@
|
||||
NotEmptyValue="Visible" />
|
||||
|
||||
<DataTemplate x:Key="TagTemplate" x:DataType="viewmodels:TagViewModel">
|
||||
<ItemContainer>
|
||||
<cpcontrols:Tag
|
||||
BackgroundColor="{x:Bind Background, Mode=OneWay}"
|
||||
FontSize="12"
|
||||
ForegroundColor="{x:Bind Foreground, Mode=OneWay}"
|
||||
Icon="{x:Bind Icon, Mode=OneWay}"
|
||||
Text="{x:Bind Text, Mode=OneWay}"
|
||||
ToolTipService.ToolTip="{x:Bind ToolTip, Mode=OneWay}" />
|
||||
</ItemContainer>
|
||||
<cpcontrols:Tag
|
||||
AutomationProperties.Name="{x:Bind Text, Mode=OneWay}"
|
||||
BackgroundColor="{x:Bind Background, Mode=OneWay}"
|
||||
FontSize="12"
|
||||
ForegroundColor="{x:Bind Foreground, Mode=OneWay}"
|
||||
Icon="{x:Bind Icon, Mode=OneWay}"
|
||||
Text="{x:Bind Text, Mode=OneWay}"
|
||||
ToolTipService.ToolTip="{x:Bind ToolTip, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
|
||||
<!-- https://learn.microsoft.com/windows/apps/design/controls/itemsview#specify-the-look-of-the-items -->
|
||||
<DataTemplate x:Key="ListItemViewModelTemplate" x:DataType="viewmodels:ListItemViewModel">
|
||||
|
||||
<Grid Padding="0,12,0,12" ColumnSpacing="12">
|
||||
<Grid
|
||||
Padding="0,12,0,12"
|
||||
AutomationProperties.Name="{x:Bind Title, Mode=OneWay}"
|
||||
ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="28" />
|
||||
<ColumnDefinition Width="*" />
|
||||
@@ -55,6 +56,7 @@
|
||||
Width="20"
|
||||
Height="20"
|
||||
Margin="4,0,4,0"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using CmdPalKeyboardService;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CmdPal.Common.Helpers;
|
||||
using Microsoft.CmdPal.Common.Messages;
|
||||
@@ -52,6 +53,8 @@ public sealed partial class MainWindow : Window,
|
||||
#pragma warning restore SA1306 // Field names should begin with lower-case letter
|
||||
#pragma warning restore SA1310 // Field names should not contain underscore
|
||||
|
||||
private readonly KeyboardListener _keyboardListener;
|
||||
|
||||
// Notification Area ("Tray") icon data
|
||||
private NOTIFYICONDATAW? _trayIconData;
|
||||
private DestroyIconSafeHandle? _largeIcon;
|
||||
@@ -66,6 +69,11 @@ public sealed partial class MainWindow : Window,
|
||||
_hwnd = new HWND(WinRT.Interop.WindowNative.GetWindowHandle(this).ToInt32());
|
||||
CommandPaletteHost.SetHostHwnd((ulong)_hwnd.Value);
|
||||
|
||||
_keyboardListener = new KeyboardListener();
|
||||
_keyboardListener.Start();
|
||||
|
||||
_keyboardListener.SetProcessCommand(new CmdPalKeyboardService.ProcessCommand(HandleSummon));
|
||||
|
||||
// TaskbarCreated is the message that's broadcast when explorer.exe
|
||||
// restarts. We need to know when that happens to be able to bring our
|
||||
// notification area icon back
|
||||
@@ -278,16 +286,12 @@ public sealed partial class MainWindow : Window,
|
||||
ShowHwnd(message.Hwnd, settings.SummonOn);
|
||||
}
|
||||
|
||||
public void Receive(HideWindowMessage message)
|
||||
{
|
||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
}
|
||||
public void Receive(HideWindowMessage message) => PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
|
||||
public void Receive(QuitMessage message) =>
|
||||
|
||||
public void Receive(QuitMessage message)
|
||||
{
|
||||
// This might come in on a background thread
|
||||
DispatcherQueue.TryEnqueue(() => Close());
|
||||
}
|
||||
|
||||
public void Receive(DismissMessage message) =>
|
||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
@@ -304,6 +308,8 @@ public sealed partial class MainWindow : Window,
|
||||
// Workaround by turning it off before shutdown.
|
||||
App.Current.DebugSettings.FailFastOnErrors = false;
|
||||
DisposeAcrylic();
|
||||
|
||||
_keyboardListener.Stop();
|
||||
}
|
||||
|
||||
private void DisposeAcrylic()
|
||||
@@ -368,12 +374,17 @@ public sealed partial class MainWindow : Window,
|
||||
// ... then don't hide the window when it loses focus.
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalDismissedOnLostFocus());
|
||||
// Are we disabled? If we are, then we don't want to dismiss on focus lost.
|
||||
// This can happen if an extension wanted to show a modal dialog on top of our
|
||||
// window i.e. in the case of an MSAL auth window.
|
||||
if (PInvoke.IsWindowEnabled(_hwnd) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalDismissedOnLostFocus());
|
||||
}
|
||||
|
||||
if (_configurationSource != null)
|
||||
@@ -382,14 +393,13 @@ public sealed partial class MainWindow : Window,
|
||||
}
|
||||
}
|
||||
|
||||
public void Summon(string commandId)
|
||||
{
|
||||
public void Summon(string commandId) =>
|
||||
|
||||
// The actual showing and hiding of the window will be done by the
|
||||
// ShellPage. This is because we don't want to show the window if the
|
||||
// user bound a hotkey to just an invokable command, which we can't
|
||||
// know till the message is being handled.
|
||||
WeakReferenceMessenger.Default.Send<HotkeySummonMessage>(new(commandId, _hwnd));
|
||||
}
|
||||
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
private const uint DOT_KEY = 0xBE;
|
||||
@@ -398,6 +408,8 @@ public sealed partial class MainWindow : Window,
|
||||
|
||||
private void UnregisterHotkeys()
|
||||
{
|
||||
_keyboardListener.ClearHotkeys();
|
||||
|
||||
while (_hotkeys.Count > 0)
|
||||
{
|
||||
PInvoke.UnregisterHotKey(_hwnd, _hotkeys.Count - 1);
|
||||
@@ -412,19 +424,28 @@ public sealed partial class MainWindow : Window,
|
||||
var globalHotkey = settings.Hotkey;
|
||||
if (globalHotkey != null)
|
||||
{
|
||||
var vk = globalHotkey.Code;
|
||||
var modifiers =
|
||||
(globalHotkey.Alt ? HOT_KEY_MODIFIERS.MOD_ALT : 0) |
|
||||
(globalHotkey.Ctrl ? HOT_KEY_MODIFIERS.MOD_CONTROL : 0) |
|
||||
(globalHotkey.Shift ? HOT_KEY_MODIFIERS.MOD_SHIFT : 0) |
|
||||
(globalHotkey.Win ? HOT_KEY_MODIFIERS.MOD_WIN : 0)
|
||||
;
|
||||
|
||||
var success = PInvoke.RegisterHotKey(_hwnd, _hotkeys.Count, modifiers, (uint)vk);
|
||||
if (success)
|
||||
if (settings.UseLowLevelGlobalHotkey)
|
||||
{
|
||||
_keyboardListener.SetHotkeyAction(globalHotkey.Win, globalHotkey.Ctrl, globalHotkey.Shift, globalHotkey.Alt, (byte)globalHotkey.Code, string.Empty);
|
||||
|
||||
_hotkeys.Add(new(globalHotkey, string.Empty));
|
||||
}
|
||||
else
|
||||
{
|
||||
var vk = globalHotkey.Code;
|
||||
var modifiers =
|
||||
(globalHotkey.Alt ? HOT_KEY_MODIFIERS.MOD_ALT : 0) |
|
||||
(globalHotkey.Ctrl ? HOT_KEY_MODIFIERS.MOD_CONTROL : 0) |
|
||||
(globalHotkey.Shift ? HOT_KEY_MODIFIERS.MOD_SHIFT : 0) |
|
||||
(globalHotkey.Win ? HOT_KEY_MODIFIERS.MOD_WIN : 0)
|
||||
;
|
||||
|
||||
var success = PInvoke.RegisterHotKey(_hwnd, _hotkeys.Count, modifiers, (uint)vk);
|
||||
if (success)
|
||||
{
|
||||
_hotkeys.Add(new(globalHotkey, string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var commandHotkey in settings.CommandHotkeys)
|
||||
@@ -450,6 +471,26 @@ public sealed partial class MainWindow : Window,
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSummon(string commandId)
|
||||
{
|
||||
var isRootHotkey = string.IsNullOrEmpty(commandId);
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalHotkeySummoned(isRootHotkey));
|
||||
|
||||
// Note to future us: the wParam will have the index of the hotkey we registered.
|
||||
// We can use that in the future to differentiate the hotkeys we've pressed
|
||||
// so that we can bind hotkeys to individual commands
|
||||
if (!this.Visible || !isRootHotkey)
|
||||
{
|
||||
Activate();
|
||||
|
||||
Summon(commandId);
|
||||
}
|
||||
else if (isRootHotkey)
|
||||
{
|
||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
private LRESULT HotKeyPrc(
|
||||
HWND hwnd,
|
||||
uint uMsg,
|
||||
@@ -464,22 +505,23 @@ public sealed partial class MainWindow : Window,
|
||||
if (hotkeyIndex < _hotkeys.Count)
|
||||
{
|
||||
var hotkey = _hotkeys[hotkeyIndex];
|
||||
var isRootHotkey = string.IsNullOrEmpty(hotkey.CommandId);
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalHotkeySummoned(isRootHotkey));
|
||||
HandleSummon(hotkey.CommandId);
|
||||
|
||||
// Note to future us: the wParam will have the index of the hotkey we registered.
|
||||
// We can use that in the future to differentiate the hotkeys we've pressed
|
||||
// so that we can bind hotkeys to individual commands
|
||||
if (!this.Visible || !isRootHotkey)
|
||||
{
|
||||
Activate();
|
||||
// var isRootHotkey = string.IsNullOrEmpty(hotkey.CommandId);
|
||||
|
||||
Summon(hotkey.CommandId);
|
||||
}
|
||||
else if (isRootHotkey)
|
||||
{
|
||||
PInvoke.ShowWindow(hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
}
|
||||
// // Note to future us: the wParam will have the index of the hotkey we registered.
|
||||
// // We can use that in the future to differentiate the hotkeys we've pressed
|
||||
// // so that we can bind hotkeys to individual commands
|
||||
// if (!this.Visible || !isRootHotkey)
|
||||
// {
|
||||
// Activate();
|
||||
|
||||
// Summon(hotkey.CommandId);
|
||||
// }
|
||||
// else if (isRootHotkey)
|
||||
// {
|
||||
// PInvoke.ShowWindow(hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
// }
|
||||
}
|
||||
|
||||
return (LRESULT)IntPtr.Zero;
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(CIBuild)'=='true'">
|
||||
<PropertyGroup>
|
||||
<GenerateAppxPackageOnBuild>true</GenerateAppxPackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- This lets us actually reference types from Microsoft.Terminal.UI -->
|
||||
<CsWinRTIncludes>Microsoft.Terminal.UI</CsWinRTIncludes>
|
||||
<CsWinRTIncludes>Microsoft.Terminal.UI;CmdPalKeyboardService</CsWinRTIncludes>
|
||||
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -97,32 +97,38 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.WebSearch\Microsoft.CmdPal.Ext.WebSearch.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WebSearch\Microsoft.CmdPal.Ext.WebSearch.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.CmdPal.Common\Microsoft.CmdPal.Common.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.CmdPal.UI.ViewModels\Microsoft.CmdPal.UI.ViewModels.csproj" />
|
||||
|
||||
<ProjectReference Include="..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.Bookmark\Microsoft.CmdPal.Ext.Bookmarks.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.Calc\Microsoft.CmdPal.Ext.Calc.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.ClipboardHistory\Microsoft.CmdPal.Ext.ClipboardHistory.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.Registry\Microsoft.CmdPal.Ext.Registry.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.Shell\Microsoft.CmdPal.Ext.Shell.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.TimeDate\Microsoft.CmdPal.Ext.TimeDate.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.WindowsServices\Microsoft.CmdPal.Ext.WindowsServices.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.WindowsSettings\Microsoft.CmdPal.Ext.WindowsSettings.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.WindowsTerminal\Microsoft.CmdPal.Ext.WindowsTerminal.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.WindowWalker\Microsoft.CmdPal.Ext.WindowWalker.csproj" />
|
||||
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.WinGet\Microsoft.CmdPal.Ext.WinGet.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Bookmark\Microsoft.CmdPal.Ext.Bookmarks.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Calc\Microsoft.CmdPal.Ext.Calc.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.ClipboardHistory\Microsoft.CmdPal.Ext.ClipboardHistory.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Registry\Microsoft.CmdPal.Ext.Registry.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Shell\Microsoft.CmdPal.Ext.Shell.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.TimeDate\Microsoft.CmdPal.Ext.TimeDate.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WindowsServices\Microsoft.CmdPal.Ext.WindowsServices.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WindowsSettings\Microsoft.CmdPal.Ext.WindowsSettings.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WindowsTerminal\Microsoft.CmdPal.Ext.WindowsTerminal.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WindowWalker\Microsoft.CmdPal.Ext.WindowWalker.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WinGet\Microsoft.CmdPal.Ext.WinGet.csproj" />
|
||||
|
||||
<ProjectReference Include="..\Microsoft.Terminal.UI\Microsoft.Terminal.UI.vcxproj">
|
||||
<ReferenceOutputAssembly>True</ReferenceOutputAssembly>
|
||||
<Private>True</Private>
|
||||
<CopyLocalSatelliteAssemblies>True</CopyLocalSatelliteAssemblies>
|
||||
</ProjectReference>
|
||||
|
||||
<ProjectReference Include="..\CmdPalKeyboardService\CmdPalKeyboardService.vcxproj">
|
||||
<ReferenceOutputAssembly>True</ReferenceOutputAssembly>
|
||||
<Private>True</Private>
|
||||
<CopyLocalSatelliteAssemblies>True</CopyLocalSatelliteAssemblies>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -15,6 +15,7 @@ CallWindowProc
|
||||
ShowWindow
|
||||
SetForegroundWindow
|
||||
EnableWindow
|
||||
IsWindowEnabled
|
||||
SetFocus
|
||||
SetActiveWindow
|
||||
MonitorFromWindow
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<DataTemplate x:Key="TagTemplate" x:DataType="viewModels:TagViewModel">
|
||||
<cpcontrols:Tag
|
||||
HorizontalAlignment="Left"
|
||||
AutomationProperties.Name="{x:Bind Text, Mode=OneWay}"
|
||||
BackgroundColor="{x:Bind Background, Mode=OneWay}"
|
||||
FontSize="12"
|
||||
ForegroundColor="{x:Bind Foreground, Mode=OneWay}"
|
||||
@@ -147,27 +148,36 @@
|
||||
Visibility="{x:Bind ViewModel.CurrentPage.IsNested, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
|
||||
<animations:Implicit.ShowAnimations>
|
||||
<animations:OpacityAnimation
|
||||
EasingMode="EaseIn"
|
||||
EasingType="Cubic"
|
||||
From="0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.340" />
|
||||
Duration="0:0:0.187" />
|
||||
<animations:ScaleAnimation
|
||||
EasingMode="EaseIn"
|
||||
EasingType="Cubic"
|
||||
From="0.5"
|
||||
To="1"
|
||||
Duration="0:0:0.350" />
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.ShowAnimations>
|
||||
<animations:Implicit.HideAnimations>
|
||||
<animations:OpacityAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="1.0"
|
||||
To="0"
|
||||
Duration="0:0:0.240" />
|
||||
Duration="0:0:0.187" />
|
||||
<animations:ScaleAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="1"
|
||||
To="0.5"
|
||||
Duration="0:0:0.350" />
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.HideAnimations>
|
||||
</Image>
|
||||
<Button
|
||||
x:Name="BackButton"
|
||||
x:Uid="BackButton"
|
||||
Margin="4,0,4,0"
|
||||
Padding="4"
|
||||
HorizontalAlignment="Center"
|
||||
@@ -178,35 +188,42 @@
|
||||
FontSize="16"
|
||||
Style="{StaticResource SubtleButtonStyle}"
|
||||
Tapped="BackButton_Tapped"
|
||||
ToolTipService.ToolTip="Back"
|
||||
Visibility="{x:Bind ViewModel.CurrentPage.IsNested, Mode=OneWay}">
|
||||
<animations:Implicit.ShowAnimations>
|
||||
<animations:OpacityAnimation
|
||||
EasingMode="EaseIn"
|
||||
EasingType="Cubic"
|
||||
From="0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.340" />
|
||||
Duration="0:0:0.333" />
|
||||
<animations:ScaleAnimation
|
||||
From="0.5"
|
||||
To="1"
|
||||
Duration="0:0:0.350" />
|
||||
Duration="0:0:0.333" />
|
||||
<animations:TranslationAnimation
|
||||
From="16,0,0"
|
||||
To="0,0,0"
|
||||
Duration="0:0:0.350" />
|
||||
Duration="0:0:0.333" />
|
||||
</animations:Implicit.ShowAnimations>
|
||||
<animations:Implicit.HideAnimations>
|
||||
<animations:OpacityAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="1.0"
|
||||
To="0"
|
||||
Duration="0:0:0.340" />
|
||||
Duration="0:0:0.333" />
|
||||
<animations:ScaleAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="1"
|
||||
To="0.5"
|
||||
Duration="0:0:0.350" />
|
||||
Duration="0:0:0.333" />
|
||||
<animations:TranslationAnimation
|
||||
EasingMode="EaseOut"
|
||||
EasingType="Cubic"
|
||||
From="0,0,0"
|
||||
To="16,0,0"
|
||||
Duration="0:0:0.350" />
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.HideAnimations>
|
||||
</Button>
|
||||
<cpcontrols:IconBox
|
||||
@@ -223,29 +240,29 @@
|
||||
<animations:OpacityAnimation
|
||||
From="0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.450" />
|
||||
Duration="0:0:0.333" />
|
||||
<animations:ScaleAnimation
|
||||
From="0.8"
|
||||
To="1"
|
||||
Duration="0:0:0.500" />
|
||||
Duration="0:0:0.333" />
|
||||
<animations:TranslationAnimation
|
||||
From="8,0,0"
|
||||
To="0,0,0"
|
||||
Duration="0:0:0.400" />
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.ShowAnimations>
|
||||
<animations:Implicit.HideAnimations>
|
||||
<animations:OpacityAnimation
|
||||
From="1.0"
|
||||
To="0"
|
||||
Duration="0:0:0.340" />
|
||||
Duration="0:0:0.333" />
|
||||
<animations:ScaleAnimation
|
||||
From="1"
|
||||
To="0.8"
|
||||
Duration="0:0:0.350" />
|
||||
Duration="0:0:0.333" />
|
||||
<animations:TranslationAnimation
|
||||
From="0,0,0"
|
||||
To="8,0,0"
|
||||
Duration="0:0:0.350" />
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.HideAnimations>
|
||||
</cpcontrols:IconBox>
|
||||
</StackPanel>
|
||||
@@ -272,13 +289,13 @@
|
||||
<animations:OpacityAnimation
|
||||
From="0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.340" />
|
||||
Duration="0:0:0.333" />
|
||||
</animations:Implicit.ShowAnimations>
|
||||
<animations:Implicit.HideAnimations>
|
||||
<animations:OpacityAnimation
|
||||
From="1.0"
|
||||
To="0"
|
||||
Duration="0:0:0.340" />
|
||||
Duration="0:0:0.333" />
|
||||
</animations:Implicit.HideAnimations>
|
||||
</ProgressBar>
|
||||
|
||||
@@ -313,21 +330,21 @@
|
||||
<animations:OpacityAnimation
|
||||
From="0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.270" />
|
||||
Duration="0:0:0.187" />
|
||||
<animations:TranslationAnimation
|
||||
From="24,0,0"
|
||||
To="0,0,0"
|
||||
Duration="0:0:0.280" />
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.ShowAnimations>
|
||||
<animations:Implicit.HideAnimations>
|
||||
<animations:OpacityAnimation
|
||||
From="1.0"
|
||||
To="0"
|
||||
Duration="0:0:0.180" />
|
||||
Duration="0:0:0.187" />
|
||||
<animations:TranslationAnimation
|
||||
From="0,0,0"
|
||||
To="24,0,0"
|
||||
Duration="0:0:0.220" />
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.HideAnimations>
|
||||
<Grid Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -343,6 +360,7 @@
|
||||
MinHeight="64"
|
||||
MaxHeight="96"
|
||||
HorizontalAlignment="Center"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
SourceKey="{x:Bind ViewModel.Details.HeroImage, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}"
|
||||
Visibility="{x:Bind HasHeroImage, Mode=OneWay}" />
|
||||
|
||||
@@ -187,6 +187,8 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
||||
|
||||
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(null));
|
||||
|
||||
WeakReferenceMessenger.Default.Send<UpdateItemKeybindingsMessage>(new(null));
|
||||
|
||||
var isMainPage = command is MainListPage;
|
||||
|
||||
// Construct our ViewModel of the appropriate type and pass it the UI Thread context.
|
||||
@@ -427,8 +429,6 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
||||
}
|
||||
|
||||
_settingsWindow.Activate();
|
||||
|
||||
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(null));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,18 @@
|
||||
|
||||
<TextBlock x:Uid="ActivationSettingsHeader" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="Settings_GeneralPage_ActivationKey_SettingsExpander" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:SettingsExpander
|
||||
x:Uid="Settings_GeneralPage_ActivationKey_SettingsExpander"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ptControls:ShortcutControl HotkeySettings="{x:Bind viewModel.Hotkey, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<controls:SettingsExpander.Items>
|
||||
<controls:SettingsCard x:Uid="Settings_GeneralPage_LowLevelHook_SettingsCard">
|
||||
<ToggleSwitch IsOn="{x:Bind viewModel.UseLowLevelGlobalHotkey, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
</controls:SettingsExpander>
|
||||
<controls:SettingsCard x:Uid="Settings_GeneralPage_GoHome_SettingsCard" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind viewModel.HotkeyGoesHome, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
@@ -322,6 +322,12 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="Settings_GeneralPage_ActivationKey_SettingsExpander.Description" xml:space="preserve">
|
||||
<value>This key will open the Command Palette.</value>
|
||||
</data>
|
||||
<data name="Settings_GeneralPage_LowLevelHook_SettingsCard.Header" xml:space="preserve">
|
||||
<value>Use low-level keyboard hook</value>
|
||||
</data>
|
||||
<data name="Settings_GeneralPage_LowLevelHook_SettingsCard.Description" xml:space="preserve">
|
||||
<value>Try this if there are issues with the shortcut (Command Palette might not get focus when triggered from an elevated window)</value>
|
||||
</data>
|
||||
<data name="Settings_GeneralPage_GoHome_SettingsCard.Header" xml:space="preserve">
|
||||
<value>Go home when activated</value>
|
||||
</data>
|
||||
@@ -373,9 +379,6 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="Settings_GeneralPage_NavigationViewItem_Extensions.Content" xml:space="preserve">
|
||||
<value>Extensions</value>
|
||||
</data>
|
||||
<data name="MoreCommandsButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>More commands</value>
|
||||
</data>
|
||||
<data name="SettingsButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Open Command Palette settings</value>
|
||||
</data>
|
||||
@@ -391,4 +394,13 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="Settings_GeneralPage_ShowSystemTrayIcon_SettingsCard.Description" xml:space="preserve">
|
||||
<value>Choose if Command Palette is visible in the system tray</value>
|
||||
</data>
|
||||
<data name="BackButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="BackButton.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="MoreCommandsButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>More</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -152,7 +152,7 @@ We've made it easy to build a new extension. Just follow these steps:
|
||||
2. Run the following PowerShell script, replacing "MastodonExtension" with the `Name` of your extension and "Mastodon extension for cmdpal" with the `DisplayName` of the [command that will show up in the root view](#root-view) of the Command Palette:
|
||||
|
||||
```powershell
|
||||
.\Exts\NewExtension.ps1 -name MastodonExtension -DisplayName "Mastodon extension for cmdpal"
|
||||
.\ext\NewExtension.ps1 -name MastodonExtension -DisplayName "Mastodon extension for cmdpal"
|
||||
```
|
||||
|
||||
3. Open the solution in Visual Studio.
|
||||
|
||||
@@ -57,7 +57,7 @@ public sealed partial class AllAppsPage : ListPage
|
||||
Stopwatch stopwatch = new();
|
||||
stopwatch.Start();
|
||||
|
||||
List<AppItem> apps = GetPrograms();
|
||||
var apps = GetPrograms();
|
||||
|
||||
this.allAppsSection = apps
|
||||
.Select((app) => new AppListItem(app, true))
|
||||
@@ -73,26 +73,15 @@ public sealed partial class AllAppsPage : ListPage
|
||||
|
||||
internal List<AppItem> GetPrograms()
|
||||
{
|
||||
IEnumerable<AppItem> uwpResults = AppCache.Instance.Value.UWPs
|
||||
var uwpResults = AppCache.Instance.Value.UWPs
|
||||
.Where((application) => application.Enabled)
|
||||
.Select(app =>
|
||||
new AppItem()
|
||||
{
|
||||
Name = app.Name,
|
||||
Subtitle = app.Description,
|
||||
Type = UWPApplication.Type(),
|
||||
IcoPath = app.LogoType != LogoType.Error ? app.LogoPath : string.Empty,
|
||||
DirPath = app.Location,
|
||||
UserModelId = app.UserModelId,
|
||||
IsPackaged = true,
|
||||
Commands = app.GetCommands(),
|
||||
});
|
||||
.Select(UwpToAppItem);
|
||||
|
||||
IEnumerable<AppItem> win32Results = AppCache.Instance.Value.Win32s
|
||||
var win32Results = AppCache.Instance.Value.Win32s
|
||||
.Where((application) => application.Enabled && application.Valid)
|
||||
.Select(app =>
|
||||
{
|
||||
string icoPath = string.IsNullOrEmpty(app.IcoPath) ?
|
||||
var icoPath = string.IsNullOrEmpty(app.IcoPath) ?
|
||||
(app.AppType == Win32Program.ApplicationType.InternetShortcutApplication ?
|
||||
app.IcoPath :
|
||||
app.FullPath) :
|
||||
@@ -116,4 +105,21 @@ public sealed partial class AllAppsPage : ListPage
|
||||
|
||||
return uwpResults.Concat(win32Results).OrderBy(app => app.Name).ToList();
|
||||
}
|
||||
|
||||
private AppItem UwpToAppItem(UWPApplication app)
|
||||
{
|
||||
var iconPath = app.LogoType != LogoType.Error ? app.LogoPath : string.Empty;
|
||||
var item = new AppItem()
|
||||
{
|
||||
Name = app.Name,
|
||||
Subtitle = app.Description,
|
||||
Type = UWPApplication.Type(),
|
||||
IcoPath = iconPath,
|
||||
DirPath = app.Location,
|
||||
UserModelId = app.UserModelId,
|
||||
IsPackaged = true,
|
||||
Commands = app.GetCommands(),
|
||||
};
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,13 @@ internal sealed partial class AppListItem : ListItem
|
||||
Tags = [_appTag];
|
||||
MoreCommands = _app.Commands!.ToArray();
|
||||
|
||||
_details = new Lazy<Details>(() => BuildDetails());
|
||||
_details = new Lazy<Details>(() =>
|
||||
{
|
||||
var t = BuildDetails();
|
||||
t.Wait();
|
||||
return t.Result;
|
||||
});
|
||||
|
||||
_icon = new Lazy<IconInfo>(() =>
|
||||
{
|
||||
var t = FetchIcon(useThumbnails);
|
||||
@@ -41,8 +47,9 @@ internal sealed partial class AppListItem : ListItem
|
||||
});
|
||||
}
|
||||
|
||||
private Details BuildDetails()
|
||||
private async Task<Details> BuildDetails()
|
||||
{
|
||||
// Build metadata, with app type, path, etc.
|
||||
var metadata = new List<DetailsElement>();
|
||||
metadata.Add(new DetailsElement() { Key = "Type", Data = new DetailsTags() { Tags = [new Tag(_app.Type)] } });
|
||||
if (!_app.IsPackaged)
|
||||
@@ -50,10 +57,33 @@ internal sealed partial class AppListItem : ListItem
|
||||
metadata.Add(new DetailsElement() { Key = "Path", Data = new DetailsLink() { Text = _app.ExePath } });
|
||||
}
|
||||
|
||||
// Icon
|
||||
IconInfo? heroImage = null;
|
||||
if (_app.IsPackaged)
|
||||
{
|
||||
heroImage = new IconInfo(_app.IcoPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var stream = await ThumbnailHelper.GetThumbnail(_app.ExePath, true);
|
||||
if (stream != null)
|
||||
{
|
||||
heroImage = IconInfo.FromStream(stream);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// do nothing if we fail to load an icon.
|
||||
// Logging it would be too NOISY, there's really no need.
|
||||
}
|
||||
}
|
||||
|
||||
return new Details()
|
||||
{
|
||||
Title = this.Title,
|
||||
HeroImage = this.Icon ?? new IconInfo(string.Empty),
|
||||
HeroImage = heroImage ?? this.Icon ?? new IconInfo(string.Empty),
|
||||
Metadata = metadata.ToArray(),
|
||||
};
|
||||
}
|
||||
@@ -64,11 +94,6 @@ internal sealed partial class AppListItem : ListItem
|
||||
if (_app.IsPackaged)
|
||||
{
|
||||
icon = new IconInfo(_app.IcoPath);
|
||||
if (_details.IsValueCreated)
|
||||
{
|
||||
_details.Value.HeroImage = icon;
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
@@ -94,11 +119,6 @@ internal sealed partial class AppListItem : ListItem
|
||||
icon = new IconInfo(_app.IcoPath);
|
||||
}
|
||||
|
||||
if (_details.IsValueCreated)
|
||||
{
|
||||
_details.Value.HeroImage = icon;
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -6,13 +6,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Microsoft.CmdPal.Ext.Apps.Commands;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using static Microsoft.CmdPal.Ext.Apps.Utils.Native;
|
||||
using PackageVersion = Microsoft.CmdPal.Ext.Apps.Programs.UWP.PackageVersion;
|
||||
@@ -314,7 +312,12 @@ public class UWPApplication : IProgram
|
||||
}
|
||||
}
|
||||
|
||||
var selectedIconPath = paths.FirstOrDefault(File.Exists);
|
||||
// By working from the highest resolution to the lowest, we make
|
||||
// sure that we use the highest quality possible icon for the app.
|
||||
//
|
||||
// FirstOrDefault would result in us using the 1x scaled icon
|
||||
// always, which is usually too small for our needs.
|
||||
var selectedIconPath = paths.LastOrDefault(File.Exists);
|
||||
if (!string.IsNullOrEmpty(selectedIconPath))
|
||||
{
|
||||
LogoPath = selectedIconPath;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user