Compare commits

...

19 Commits

Author SHA1 Message Date
Yu Leng (from Dev Box)
a19fc93346 Rename func 2025-04-15 16:09:42 +08:00
Yu Leng (from Dev Box)
85bdeeaacf init 2025-04-15 15:14:34 +08:00
Stefan Markovic
f1bda8d71f [cmdpal] Setting a new alias should remove the old one (#38193)
* [cmdpal] Fix alias update

* Fix the command palette extension alias update issue

* clean code

---------

Co-authored-by: vanzue <vanzue@outlook.com>
2025-04-15 13:09:35 +08:00
PesBandi
21aa49cefb [ColorPicker]Only close on escape if focused (#37895) 2025-04-15 11:15:41 +08:00
ruslanlap
293fa262bb [PowerToysRun][Docs] Add Weather and Pomodoro to Third-Party plugins (#38760)
* [PowerToysRun][Docs] Add Weather and Pomodoro to Third-Party plugins

* [Spell-check] Add ruslanlap to allowed names and update expect.txt

* Update expect.txt

* Update names.txt

* Update names.txt

* Update names.txt

* Update names.txt
2025-04-14 17:02:29 +00:00
Clint Rutkas
578d99f3b3 upgrading to adjust fix vulnerability (#38784)
* upgrading to adjust fix vulnerablitlity

* Update NOTICE.md

* Update NuGet packages in NOTICE.md
2025-04-14 17:01:54 +00:00
Clint Rutkas
badb029bcf Upgrading some of the Testing framework items (#38779)
* starting to get some of the baseline

* Update NOTICE.md

* Upgrading streamjson gets the others on same version of newtonsoft.json

* Update PowerToys.Settings.csproj

* Update NOTICE.md
2025-04-14 17:01:37 +00:00
dcog989
bec6754aa3 Fix Color Picker resource leak (#38122) (#38147)
* Fix Color Picker resource leak (#38122)

Added a using statement to properly dispose of the Graphics object created from the Bitmap. This fixes resource leak.

* Fix CI complain

* Update MouseInfoProvider.cs

fix whitespace

---------

Co-authored-by: Kai Tao <69313318+vanzue@users.noreply.github.com>
2025-04-14 18:20:55 +08:00
OlegHarchevkin
d986592737 "ǔ" changed to "ŭ" in GetDefaultLetterKeyEPO (#37791) 2025-04-14 16:50:00 +08:00
Ionuț Manța
662f04ed34 [KeyboardManager] Fix modifier Key (Not right or left) stuck (#37930)
* Fix ctr,alt,shift getting stuck

* more changes

* Update src/modules/keyboardmanager/common/Helpers.h

Co-authored-by: Hao Liu <liuhaobupt@163.com>

---------

Co-authored-by: Hao Liu <liuhaobupt@163.com>
2025-04-14 16:48:10 +08:00
Bennett Blodinger
03bc72c436 Change log extension from .txt => .log (#33813)
* Change log extension

From .txt to .log

* Also add workspace logs

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2025-04-14 07:20:43 +08:00
Muhammad Danish
5c8aa67781 Add securityContext to configuration files (#38017)
For the winget DSC, Setting developer mode, installing Visual Studio 2022 & fetching and installing VS components all require elevation. Added securityContext: elevated for these resources. These configurations can now be invoked from user context, and will prompt for a single UAC to run resources that require elevation in a separate process.
2025-04-14 07:19:22 +08:00
ruslanlap
b32c04fca1 [PowerToysRun][Docs] Add QuickNotes to Third-Party plugins (#38663)
* Add QuickNotes plugin to third-party Run plugins documentation

* chore: add ruslanlap to spelling allow-list

* chore: add ruslanlap to spelling allow-list

* chore: add ruslanlap to spelling allow-list

* Add ruslanlap to allowed names and remove from expected words list
2025-04-11 18:45:25 +00:00
Gordon Lam
4cb72ee126 Add Zhiwei as part of PowerToys! (#38744)
* Add Zhiwei as part of PowerToys!

* Fix the expect.txt for Zhiwei

* Fix the case problem on expect.txt zhiwei => Zhiwei
2025-04-11 12:58:10 +08:00
Davide Giacometti
55f8f3a53e [CmdPal] Tray icon settings (#38672)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request

Added a settings to enable/disable the system tray icon (enabled by default).
Adopter the term "system tray icon" for consistency with Windows 11 settings.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] **Closes:** #38407
2025-04-10 16:44:54 -05:00
Yu Leng
a7994402fe [cmdpal] Add Open URL fallback command for WebSearch ext (#38685)
## Summary of the Pull Request
1. Add new fallback command for websearch

https://github.com/user-attachments/assets/39362d66-db59-42d4-b07c-7bfd60b2e420

## PR Checklist

- [x] **Closes:** #38497

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-04-10 10:34:52 -05:00
RokyZevon
41472a483c [cmdpal] fix a broken link in README.md (#38714)
related issue: #38713
2025-04-10 09:00:33 -05:00
Laszlo Nemeth
94e8559796 [Bug report] - Auto fill bug report parameters. (#37991) 2025-04-10 16:29:06 +08:00
Clint Rutkas
fe53a9c89a empowering users to maximize OOBE to their heart desire (#37823)
empowering users to maximize to their heart desire
2025-04-09 22:27:17 -07:00
54 changed files with 622 additions and 283 deletions

View File

@@ -6,12 +6,16 @@ properties:
directives:
description: Enable Developer Mode
allowPrerelease: true
# Requires elevation for the set operation
securityContext: elevated
settings:
Ensure: Present
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: vsPackage
directives:
description: Install Visual Studio 2022 Enterprise (Any edition will work)
# Requires elevation for the set operation
securityContext: elevated
settings:
id: Microsoft.VisualStudio.2022.Enterprise
source: winget
@@ -21,6 +25,8 @@ properties:
directives:
description: Install required VS workloads
allowPrerelease: true
# Requires elevation for the get and set operations
securityContext: elevated
settings:
productId: Microsoft.VisualStudio.Product.Enterprise
channelId: VisualStudio.17.Release

View File

@@ -6,12 +6,16 @@ properties:
directives:
description: Enable Developer Mode
allowPrerelease: true
# Requires elevation for the set operation
securityContext: elevated
settings:
Ensure: Present
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: vsPackage
directives:
description: Install Visual Studio 2022 Professional (Any edition will work)
# Requires elevation for the set operation
securityContext: elevated
settings:
id: Microsoft.VisualStudio.2022.Professional
source: winget
@@ -21,6 +25,8 @@ properties:
directives:
description: Install required VS workloads
allowPrerelease: true
# Requires elevation for the get and set operations
securityContext: elevated
settings:
productId: Microsoft.VisualStudio.Product.Professional
channelId: VisualStudio.17.Release

View File

@@ -6,12 +6,16 @@ properties:
directives:
description: Enable Developer Mode
allowPrerelease: true
# Requires elevation for the set operation
securityContext: elevated
settings:
Ensure: Present
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: vsPackage
directives:
description: Install Visual Studio 2022 Community (Any edition will work)
# Requires elevation for the set operation
securityContext: elevated
settings:
id: Microsoft.VisualStudio.2022.Community
source: winget
@@ -21,6 +25,8 @@ properties:
directives:
description: Install required VS workloads
allowPrerelease: true
# Requires elevation for the get and set operations
securityContext: elevated
settings:
productId: Microsoft.VisualStudio.Product.Community
channelId: VisualStudio.17.Release

View File

@@ -1,6 +1,5 @@
name: "🕷️ Bug report"
description: Report errors or unexpected behavior
type: Bug
labels:
- Issue-Bug
- Needs-Triage
@@ -8,7 +7,8 @@ body:
- type: markdown
attributes:
value: Please make sure to [search for existing issues](https://github.com/microsoft/PowerToys/issues) before filing a new one!
- type: input
- id: version
type: input
attributes:
label: Microsoft PowerToys version
placeholder: X.XX.X
@@ -16,7 +16,8 @@ body:
validations:
required: true
- type: dropdown
- id: installed
type: dropdown
attributes:
label: Installation method
description: How / Where was PowerToys installed from?
@@ -33,14 +34,6 @@ body:
validations:
required: true
- type: dropdown
attributes:
label: Running as admin
description: Are you running PowerToys as Admin?
options:
- "Yes"
- "No"
- type: dropdown
attributes:
label: Area(s) with issue?
@@ -67,7 +60,7 @@ body:
- Keyboard Manager
- Mouse Utilities
- Mouse Without Borders
- New+
- New+
- Peek
- PowerRename
- PowerToys Run
@@ -106,6 +99,19 @@ body:
validations:
required: false
- id: additionalInfo
type: textarea
attributes:
label: Additional Information
placeholder: |
OS version
.Net version
System Language
User or System Installation
Running as admin
validations:
required: false
- type: textarea
attributes:
label: Other Software
@@ -116,3 +122,4 @@ body:
My Cool Application v0.3 (include a code snippet if it would help!)
validations:
required: false

View File

@@ -188,6 +188,7 @@ zhaoqpcn
Zoltan
Zykova
Sameerjs
ruslanlap
# OTHERS

View File

@@ -56,12 +56,10 @@ APIIs
Apm
APPBARDATA
APPEXECLINK
APPICONREFERENCE
APPLICATIONFRAMEHOST
appmanifest
APPMODEL
APPNAME
APPPUBLISHER
appref
appsettings
appwindow
@@ -173,7 +171,6 @@ CCHFORMNAME
CCom
CContext
CDeclaration
cdn
CElems
CENTERALIGN
certlm
@@ -254,8 +251,6 @@ createdump
CREATEPROCESS
CREATESCHEDULEDTASK
CREATESTRUCT
CREATETHREAD
CREATEWINDOW
CREATEWINDOWFAILED
CRECT
CRH
@@ -308,11 +303,7 @@ DCOM
DComposition
DCR
ddd
DDEAPPLICATION
DDECOMMAND
DDEIf
DDEIFEXEC
DDETOPIC
DDevice
DDxgi
Deact
@@ -326,16 +317,13 @@ DEFAULTFLAGS
DEFAULTICON
defaultlib
DEFAULTONLY
DEFAULTTOFOLDER
DEFAULTTONEAREST
DEFAULTTONULL
DEFAULTTOPRIMARY
DEFAULTTOSTAR
DEFERERASE
DEFPUSHBUTTON
deinitialization
DELA
DELEGATEEXECUTE
DELETEDKEYIMAGE
DELETESCANS
deletethis
@@ -389,7 +377,6 @@ dreamsofameaningfullife
drivedetectionwarning
Droid
DROPFILES
DROPTARGET
DSTINVERT
DSurface
DTexture
@@ -510,12 +497,10 @@ Fira
FIXEDFILEINFO
FIXEDSYS
flac
flaticon
flyouts
FMask
fmtid
FOF
WANTNUKEWARNING
FOFX
FOLDERID
folderpath
@@ -525,7 +510,6 @@ FORCEMINIMIZE
FORMATDLGORD
formatetc
FORPARSING
fpvm
Fqc
FRAMECHANGED
frm
@@ -559,7 +543,6 @@ GETSECKEY
GETSTICKYKEYS
GETTEXTLENGTH
GHND
gifv
GMEM
GNumber
gpedit
@@ -653,7 +636,6 @@ HROW
hsb
HSCROLL
hsi
HSSH
HTCLIENT
hthumbnail
HTOUCHINPUT
@@ -691,7 +673,6 @@ iextn
IFACEMETHOD
IFACEMETHODIMP
IFile
IGNOREBASECLASS
IGNOREUNKNOWN
IGo
iid
@@ -740,8 +721,6 @@ Inste
Interlop
INTRESOURCE
INVALIDARG
INVALIDCALL
INVALIDINDEX
invalidoperatioexception
ipcmanager
IPREVIEW
@@ -803,7 +782,6 @@ LEVELID
LExit
lhwnd
LIBID
libraryincludes
LIMITSIZE
LIMITTEXT
lindex
@@ -905,7 +883,6 @@ MBM
MBR
MDICHILD
MDL
mdpvm
mdtext
mdtxt
mdwn
@@ -1053,7 +1030,6 @@ NOCRLF
nodeca
NODRAWCAPTION
NODRAWICON
NOFIXUPS
NOINHERITLAYOUT
NOINTERFACE
NOINVERT
@@ -1069,13 +1045,11 @@ NONELEVATED
NONINFRINGEMENT
nonspace
nonstd
NOOPEN
NOOWNERZORDER
NOPARENTNOTIFY
NOPREFIX
NOREDIRECTIONBITMAP
NOREDRAW
NOREMAPCLSID
NOREMOVE
norename
NOREPEAT
@@ -1094,11 +1068,9 @@ NOTIFYICONDATAW
NOTIMPL
NOTOPMOST
NOTRACK
NOTRUNCATE
NOTSRCCOPY
NOTSRCERASE
NOTXORPEN
NOUSERSETTINGS
NOZORDER
NPH
npmjs
@@ -1224,6 +1196,7 @@ Podcasts
POINTERID
POINTERUPDATE
Pokedex
Pomodoro
Popups
POPUPWINDOW
POSITIONITEM
@@ -1318,7 +1291,6 @@ Quarternary
QUERYENDSESSION
QUERYOPEN
QUEUESYNC
QUICKTIP
QUNS
QXZ
RAII
@@ -1347,7 +1319,6 @@ REFCLSID
REFIID
REGCLS
regfile
REGISTERCLASSEX
REGISTERCLASSFAILED
REGISTRYHEADER
registrypath
@@ -1359,7 +1330,6 @@ REINSTALLMODE
reloadable
Relogger
remappings
REMAPRUNDLL
REMAPSUCCESSFUL
REMAPUNSUCCESSFUL
Remotable
@@ -1436,7 +1406,6 @@ SDDL
SDKDDK
sdns
searchterm
searchtext
SEARCHUI
SECONDARYDISPLAY
secpol
@@ -1484,8 +1453,6 @@ SHELLDLL
shellex
SHELLEXECUTEINFO
SHELLEXECUTEINFOW
SHELLEXTENSION
SHELLNEWVALUE
SHFILEINFO
SHFILEOPSTRUCT
SHGDN
@@ -1495,7 +1462,6 @@ SHGFIICON
SHGFILARGEICON
shinfo
shlwapi
SHNAMEMAPPING
shobjidl
SHORTCUTATLEAST
SHORTCUTMAXONEACTIONKEY
@@ -1546,7 +1512,6 @@ SNAPPROCESS
snwprintf
softline
SOURCECLIENTAREAONLY
sourced
sourcedoc
SOURCEHEADER
sourcesdirectory
@@ -1685,7 +1650,6 @@ THotkey
throughs
TIcon
TILEDWINDOW
TILEINFO
TILLSON
timedate
timediff
@@ -1699,9 +1663,6 @@ TLayout
tlb
tlbimp
tlc
TPMLEFTALIGN
TPMRETURNCMD
TMPVAR
TNP
Toolhelp
toolkitconverters
@@ -1709,6 +1670,8 @@ toolwindow
TOPDOWNDIB
TOUCHEVENTF
TOUCHINPUT
TPMLEFTALIGN
TPMRETURNCMD
TRACEHANDLE
tracelogging
tracerpt
@@ -1782,7 +1745,6 @@ USRDLL
UType
uuidv
uwp
ums
uxt
uxtheme
vabdq
@@ -1809,7 +1771,6 @@ VERTSIZE
VFT
vget
vgetq
videourl
viewmodel
VIRTKEY
VIRTUALDESK
@@ -1843,7 +1804,7 @@ vstprintf
VSTT
vswhere
Vtbl
WANTMAPPINGHANDLE
WANTNUKEWARNING
WANTPALM
wasdk
wbem
@@ -1958,7 +1919,6 @@ WUX
Wwanpp
XAxis
xclip
xdoc
XDocument
XElement
xfd
@@ -1981,13 +1941,13 @@ Yeet
YIncrement
yinle
yinyue
youtube
YPels
YResolution
YStr
YTM
YVIRTUALSCREEN
ZEROINIT
Zhiwei
zonable
zoneset
Zoneszonabletester

View File

@@ -188,6 +188,7 @@ ZoomIt source code was originally implemented by [Sysinternals](https://sysinter
- [@cinnamon-msft](https://github.com/cinnamon-msft) - Kayla Cinnamon - Lead
- [@nguyen-dows](https://github.com/nguyen-dows) - Christopher Nguyen - Product Manager
- [@craigloewen-msft](https://github.com/craigloewen-msft) - Craig Loewen - Product Manager
- [@zhiwei-ms](https://github.com/zhiwei-ms) - Zhiwei Yu - Product Manager
- [@dhowett](https://github.com/dhowett) - Dustin Howett - Dev lead
- [@yeelam-gordon](https://github.com/yeelam-gordon) - Gordon Lam - Dev lead
- [@jamrobot](https://github.com/jamrobot) - Jerry Xu - Dev lead

View File

@@ -29,7 +29,7 @@
<PackageVersion Include="Mages" Version="3.0.0" />
<PackageVersion Include="Markdig.Signed" Version="0.34.0" />
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
<PackageVersion Include="MessagePack" Version="2.5.187" />
<PackageVersion Include="MessagePack" Version="3.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.4" />
<!-- Including Microsoft.Bcl.AsyncInterfaces to force version, since it's used by Microsoft.SemanticKernel. -->
@@ -61,7 +61,7 @@
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />
<!-- Moq to stay below v4.20 due to behavior change. need to be sure fixed -->
<PackageVersion Include="Moq" Version="4.18.4" />
<PackageVersion Include="MSTest" Version="3.6.3" />
<PackageVersion Include="MSTest" Version="3.8.3" />
<PackageVersion Include="NLog" Version="5.0.4" />
<PackageVersion Include="NLog.Extensions.Logging" Version="5.3.8" />
<PackageVersion Include="NLog.Schema" Version="5.2.8" />
@@ -69,7 +69,7 @@
<PackageVersion Include="ReverseMarkdown" Version="4.1.0" />
<PackageVersion Include="ScipBe.Common.Office.OneNote" Version="3.0.1" />
<PackageVersion Include="SharpCompress" Version="0.37.2" />
<PackageVersion Include="StreamJsonRpc" Version="2.19.27" />
<PackageVersion Include="StreamJsonRpc" Version="2.21.69" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<!-- Package System.CodeDom added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Management but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="System.CodeDom" Version="9.0.4" />
@@ -84,14 +84,17 @@
<!-- Package System.Diagnostics.PerformanceCounter added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.11. -->
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.4" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.4" />
<PackageVersion Include="System.IO.Abstractions" Version="21.0.29" />
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="21.0.29" />
<PackageVersion Include="System.IO.Abstractions" Version="22.0.13" />
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="22.0.13" />
<PackageVersion Include="System.Management" Version="9.0.4" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<PackageVersion Include="System.Reactive" Version="6.0.1" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.4" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.4" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.4" />
<PackageVersion Include="System.Text.Json" Version="9.0.4" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageVersion Include="UnicodeInformation" Version="2.6.0" />
<PackageVersion Include="UnitsNet" Version="5.56.0" />
<PackageVersion Include="UTF.Unknown" Version="2.5.1" />

View File

@@ -1393,7 +1393,6 @@ SOFTWARE.
## NuGet Packages used by PowerToys
- AdaptiveCards.ObjectModel.WinUI3 2.0.0-beta
- AdaptiveCards.Rendering.WinUI3 2.1.0-beta
- AdaptiveCards.Templating 2.0.2
@@ -1419,7 +1418,7 @@ SOFTWARE.
- LazyCache 2.4.0
- Mages 3.0.0
- Markdig.Signed 0.34.0
- MessagePack 2.5.187
- MessagePack 3.1.3
- Microsoft.Bcl.AsyncInterfaces 9.0.4
- Microsoft.CodeAnalysis.NetAnalyzers 9.0.0
- Microsoft.Data.Sqlite 9.0.4
@@ -1445,14 +1444,14 @@ SOFTWARE.
- Microsoft.Xaml.Behaviors.Wpf 1.1.39
- ModernWpfUI 0.9.4
- Moq 4.18.4
- MSTest 3.6.3
- MSTest 3.8.3
- NLog.Extensions.Logging 5.3.8
- NLog.Schema 5.2.8
- OpenAI 2.0.0
- ReverseMarkdown 4.1.0
- ScipBe.Common.Office.OneNote 3.0.1
- SharpCompress 0.37.2
- StreamJsonRpc 2.19.27
- StreamJsonRpc 2.21.69
- StyleCop.Analyzers 1.2.0-beta.556
- System.CodeDom 9.0.4
- System.CommandLine 2.0.0-beta4.22272.1
@@ -1463,17 +1462,21 @@ SOFTWARE.
- System.Diagnostics.EventLog 9.0.4
- System.Diagnostics.PerformanceCounter 9.0.4
- System.Drawing.Common 9.0.4
- System.IO.Abstractions 21.0.29
- System.IO.Abstractions.TestingHelpers 21.0.29
- System.IO.Abstractions 22.0.13
- System.IO.Abstractions.TestingHelpers 22.0.13
- System.Management 9.0.4
- System.Net.Http 4.3.4
- System.Private.Uri 4.3.2
- System.Reactive 6.0.1
- System.Runtime.Caching 9.0.4
- System.ServiceProcess.ServiceController 9.0.4
- System.Text.Encoding.CodePages 9.0.4
- System.Text.Json 9.0.4
- System.Text.RegularExpressions 4.3.1
- UnicodeInformation 2.6.0
- UnitsNet 5.56.0
- UTF.Unknown 2.5.1
- WinUIEx 2.2.0
- WPF-UI 3.0.5
- WyHash 1.0.5

View File

@@ -43,6 +43,9 @@ Contact the developers of a plugin directly for assistance with a specific plugi
| [TailwindCSS](https://github.com/skttl/ptrun-tailwindcss) | [skttl](https://github.com/skttl) | Search the documentation of TailwindCSS |
| [HttpStatusCodes](https://github.com/grzhan/HttpStatusCodePowerToys) | [grzhan](https://github.com/grzhan) | Search for http status codes |
| [SVGL](https://github.com/Sameerjs6/powertoys-svgl) | [SameerJS6](https://github.com/SameerJS6) | Search, Browse and copy SVG logos from SVGL. |
| [QuickNotes](https://github.com/ruslanlap/CommunityPowerToysRunPlugin-QuickNotes) | [ruslanlap](https://github.com/ruslanlap) | Create, manage, and search notes directly from PowerToys Run. |
| [Weather](https://github.com/ruslanlap/PowerToysRun-Weather) | [ruslanlap](https://github.com/ruslanlap) | Get real-time weather information directly from PowerToys Run. |
| [Pomodoro](https://github.com/ruslanlap/PowerToysRun-Pomodoro) | [ruslanlap](https://github.com/ruslanlap) | Manage Pomodoro productivity sessions directly from PowerToys Run. |
## Extending software plugins

View File

@@ -25,7 +25,7 @@ namespace AllExperiments
}
// Using InvariantCulture since this is used for a log file name
var logFilePath = Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".txt");
var logFilePath = Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));

View File

@@ -54,7 +54,7 @@ namespace ManagedCommon
Directory.CreateDirectory(applicationLogPath);
}
var logFilePath = Path.Combine(applicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".txt");
var logFilePath = Path.Combine(applicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));

View File

@@ -14,6 +14,9 @@
<PackageReference Include="Appium.WebDriver" />
<PackageReference Include="MSTest" />
<PackageReference Include="System.IO.Abstractions" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Private.Uri" />
<PackageReference Include="System.Text.RegularExpressions" />
</ItemGroup>
</Project>

View File

@@ -8,49 +8,49 @@ struct LogSettings
inline const static std::wstring logLevelOption = L"logLevel";
inline const static std::string runnerLoggerName = "runner";
inline const static std::wstring logPath = L"Logs\\";
inline const static std::wstring runnerLogPath = L"RunnerLogs\\runner-log.txt";
inline const static std::wstring runnerLogPath = L"RunnerLogs\\runner-log.log";
inline const static std::string actionRunnerLoggerName = "action-runner";
inline const static std::wstring actionRunnerLogPath = L"RunnerLogs\\action-runner-log.txt";
inline const static std::wstring actionRunnerLogPath = L"RunnerLogs\\action-runner-log.log";
inline const static std::string updateLoggerName = "update";
inline const static std::wstring updateLogPath = L"UpdateLogs\\update-log.txt";
inline const static std::wstring updateLogPath = L"UpdateLogs\\update-log.log";
inline const static std::string fileExplorerLoggerName = "FileExplorer";
inline const static std::wstring fileExplorerLogPath = L"Logs\\file-explorer-log.txt";
inline const static std::wstring fileExplorerLogPath = L"Logs\\file-explorer-log.log";
inline const static std::string gcodePrevLoggerName = "GcodePrevHandler";
inline const static std::wstring gcodePrevLogPath = L"logs\\FileExplorer_localLow\\GcodePreviewHandler\\gcode-prev-handler-log.txt";
inline const static std::wstring gcodePrevLogPath = L"logs\\FileExplorer_localLow\\GcodePreviewHandler\\gcode-prev-handler-log.log";
inline const static std::string gcodeThumbLoggerName = "GcodeThumbnailProvider";
inline const static std::wstring gcodeThumbLogPath = L"logs\\FileExplorer_localLow\\GcodeThumbnailProvider\\gcode-thumbnail-provider-log.txt";
inline const static std::wstring gcodeThumbLogPath = L"logs\\FileExplorer_localLow\\GcodeThumbnailProvider\\gcode-thumbnail-provider-log.log";
inline const static std::string mdPrevLoggerName = "MDPrevHandler";
inline const static std::wstring mdPrevLogPath = L"logs\\FileExplorer_localLow\\MDPrevHandler\\md-prev-handler-log.txt";
inline const static std::wstring mdPrevLogPath = L"logs\\FileExplorer_localLow\\MDPrevHandler\\md-prev-handler-log.log";
inline const static std::string monacoPrevLoggerName = "MonacoPrevHandler";
inline const static std::wstring monacoPrevLogPath = L"logs\\FileExplorer_localLow\\MonacoPrevHandler\\monaco-prev-handler-log.txt";
inline const static std::wstring monacoPrevLogPath = L"logs\\FileExplorer_localLow\\MonacoPrevHandler\\monaco-prev-handler-log.log";
inline const static std::string pdfPrevLoggerName = "PdfPrevHandler";
inline const static std::wstring pdfPrevLogPath = L"logs\\FileExplorer_localLow\\PdfPrevHandler\\pdf-prev-handler-log.txt";
inline const static std::wstring pdfPrevLogPath = L"logs\\FileExplorer_localLow\\PdfPrevHandler\\pdf-prev-handler-log.log";
inline const static std::string pdfThumbLoggerName = "PdfThumbnailProvider";
inline const static std::wstring pdfThumbLogPath = L"logs\\FileExplorer_localLow\\PdfThumbnailProvider\\pdf-thumbnail-provider-log.txt";
inline const static std::wstring pdfThumbLogPath = L"logs\\FileExplorer_localLow\\PdfThumbnailProvider\\pdf-thumbnail-provider-log.log";
inline const static std::string qoiPrevLoggerName = "QoiPrevHandler";
inline const static std::wstring qoiPrevLogPath = L"logs\\FileExplorer_localLow\\QoiPreviewHandler\\qoi-prev-handler-log.txt";
inline const static std::wstring qoiPrevLogPath = L"logs\\FileExplorer_localLow\\QoiPreviewHandler\\qoi-prev-handler-log.log";
inline const static std::string qoiThumbLoggerName = "QoiThumbnailProvider";
inline const static std::wstring qoiThumbLogPath = L"logs\\FileExplorer_localLow\\QoiThumbnailProvider\\qoi-thumbnail-provider-log.txt";
inline const static std::wstring qoiThumbLogPath = L"logs\\FileExplorer_localLow\\QoiThumbnailProvider\\qoi-thumbnail-provider-log.log";
inline const static std::string stlThumbLoggerName = "StlThumbnailProvider";
inline const static std::wstring stlThumbLogPath = L"logs\\FileExplorer_localLow\\StlThumbnailProvider\\stl-thumbnail-provider-log.txt";
inline const static std::wstring stlThumbLogPath = L"logs\\FileExplorer_localLow\\StlThumbnailProvider\\stl-thumbnail-provider-log.log";
inline const static std::string svgPrevLoggerName = "SvgPrevHandler";
inline const static std::wstring svgPrevLogPath = L"logs\\FileExplorer_localLow\\SvgPrevHandler\\svg-prev-handler-log.txt";
inline const static std::wstring svgPrevLogPath = L"logs\\FileExplorer_localLow\\SvgPrevHandler\\svg-prev-handler-log.log";
inline const static std::string svgThumbLoggerName = "SvgThumbnailProvider";
inline const static std::wstring svgThumbLogPath = L"logs\\FileExplorer_localLow\\SvgThumbnailProvider\\svg-thumbnail-provider-log.txt";
inline const static std::wstring svgThumbLogPath = L"logs\\FileExplorer_localLow\\SvgThumbnailProvider\\svg-thumbnail-provider-log.log";
inline const static std::string launcherLoggerName = "launcher";
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.txt";
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.log";
inline const static std::string mouseWithoutBordersLoggerName = "mouseWithoutBorders";
inline const static std::wstring mouseWithoutBordersLogPath = L"LogsModuleInterface\\mouseWithoutBorders-log.txt";
inline const static std::wstring awakeLogPath = L"Logs\\awake-log.txt";
inline const static std::wstring powerAccentLogPath = L"quick-accent-log.txt";
inline const static std::wstring mouseWithoutBordersLogPath = L"LogsModuleInterface\\mouseWithoutBorders-log.log";
inline const static std::wstring awakeLogPath = L"Logs\\awake-log.log";
inline const static std::wstring powerAccentLogPath = L"quick-accent-log.log";
inline const static std::string fancyZonesLoggerName = "fancyzones";
inline const static std::wstring fancyZonesLogPath = L"fancyzones-log.txt";
inline const static std::wstring fancyZonesLogPath = L"fancyzones-log.log";
inline const static std::wstring fancyZonesOldLogPath = L"FancyZonesLogs\\"; // needed to clean up old logs
inline const static std::string shortcutGuideLoggerName = "shortcut-guide";
inline const static std::wstring shortcutGuideLogPath = L"ShortcutGuideLogs\\shortcut-guide-log.txt";
inline const static std::wstring powerOcrLogPath = L"Logs\\text-extractor-log.txt";
inline const static std::wstring shortcutGuideLogPath = L"ShortcutGuideLogs\\shortcut-guide-log.log";
inline const static std::wstring powerOcrLogPath = L"Logs\\text-extractor-log.log";
inline const static std::string keyboardManagerLoggerName = "keyboard-manager";
inline const static std::wstring keyboardManagerLogPath = L"Logs\\keyboard-manager-log.txt";
inline const static std::wstring keyboardManagerLogPath = L"Logs\\keyboard-manager-log.log";
inline const static std::string findMyMouseLoggerName = "find-my-mouse";
inline const static std::string mouseHighlighterLoggerName = "mouse-highlighter";
inline const static std::string mouseJumpLoggerName = "mouse-jump";
@@ -60,22 +60,22 @@ struct LogSettings
inline const static std::string alwaysOnTopLoggerName = "always-on-top";
inline const static std::string powerOcrLoggerName = "TextExtractor";
inline const static std::string fileLocksmithLoggerName = "FileLocksmith";
inline const static std::wstring alwaysOnTopLogPath = L"always-on-top-log.txt";
inline const static std::wstring alwaysOnTopLogPath = L"always-on-top-log.log";
inline const static std::string hostsLoggerName = "hosts";
inline const static std::wstring hostsLogPath = L"Logs\\hosts-log.txt";
inline const static std::wstring hostsLogPath = L"Logs\\hosts-log.log";
inline const static std::string registryPreviewLoggerName = "registrypreview";
inline const static std::string cropAndLockLoggerName = "crop-and-lock";
inline const static std::wstring registryPreviewLogPath = L"Logs\\registryPreview-log.txt";
inline const static std::wstring registryPreviewLogPath = L"Logs\\registryPreview-log.log";
inline const static std::string environmentVariablesLoggerName = "environment-variables";
inline const static std::wstring cmdNotFoundLogPath = L"Logs\\cmd-not-found-log.txt";
inline const static std::wstring cmdNotFoundLogPath = L"Logs\\cmd-not-found-log.log";
inline const static std::string cmdNotFoundLoggerName = "cmd-not-found";
inline const static std::string newLoggerName = "NewPlus";
inline const static std::string workspacesLauncherLoggerName = "workspaces-launcher";
inline const static std::wstring workspacesLauncherLogPath = L"workspaces-launcher-log.txt";
inline const static std::wstring workspacesLauncherLogPath = L"workspaces-launcher-log.log";
inline const static std::string workspacesWindowArrangerLoggerName = "workspaces-window-arranger";
inline const static std::wstring workspacesWindowArrangerLogPath = L"workspaces-window-arranger-log.txt";
inline const static std::wstring workspacesWindowArrangerLogPath = L"workspaces-window-arranger-log.log";
inline const static std::string workspacesSnapshotToolLoggerName = "workspaces-snapshot-tool";
inline const static std::wstring workspacesSnapshotToolLogPath = L"workspaces-snapshot-tool-log.txt";
inline const static std::wstring workspacesSnapshotToolLogPath = L"workspaces-snapshot-tool-log.log";
inline const static std::string zoomItLoggerName = "zoom-it";
inline const static int retention = 30;
std::wstring logLevel;

View File

@@ -91,7 +91,7 @@ namespace LoggerHelpers
currentFolder.append(get_product_version());
auto logsPath = currentFolder;
logsPath.append(L"log.txt");
logsPath.append(L"log.log");
Logger::init(loggerName, logsPath.wstring(), PTSettingsHelper::get_log_settings_file_location());
delete_other_versions_log_folders(rootFolder.wstring(), currentFolder);

View File

@@ -20,6 +20,9 @@
<ItemGroup>
<PackageReference Include="MSTest" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Private.Uri" />
<PackageReference Include="System.Text.RegularExpressions" />
<ProjectReference Include="..\..\..\common\UITestAutomation\UITestAutomation.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,37 @@
// 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.CmdPal.Ext.WebSearch.Helpers;
using Microsoft.CommandPalette.Extensions.Toolkit;
using BrowserInfo = Microsoft.CmdPal.Ext.WebSearch.Helpers.DefaultBrowserInfo;
namespace Microsoft.CmdPal.Ext.WebSearch.Commands;
internal sealed partial class OpenURLCommand : InvokableCommand
{
private readonly SettingsManager _settingsManager;
public string Url { get; internal set; } = string.Empty;
internal OpenURLCommand(string url, SettingsManager settingsManager)
{
Url = url;
BrowserInfo.UpdateIfTimePassed();
Icon = IconHelpers.FromRelativePath("Assets\\WebSearch.png");
Name = string.Empty;
_settingsManager = settingsManager;
}
public override CommandResult Invoke()
{
if (!ShellHelpers.OpenCommandInShell(BrowserInfo.Path, BrowserInfo.ArgumentsPattern, $"{Url}"))
{
// TODO GH# 138 --> actually display feedback from the extension somewhere.
return CommandResult.KeepOpen();
}
return CommandResult.Dismiss();
}
}

View File

@@ -0,0 +1,88 @@
// 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;
using Microsoft.CmdPal.Ext.WebSearch.Commands;
using Microsoft.CmdPal.Ext.WebSearch.Helpers;
using Microsoft.CmdPal.Ext.WebSearch.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit;
using BrowserInfo = Microsoft.CmdPal.Ext.WebSearch.Helpers.DefaultBrowserInfo;
namespace Microsoft.CmdPal.Ext.WebSearch;
internal sealed partial class FallbackOpenURLItem : FallbackCommandItem
{
private readonly OpenURLCommand _executeItem;
private static readonly CompositeFormat PluginOpenURL = System.Text.CompositeFormat.Parse(Properties.Resources.plugin_open_url);
private static readonly CompositeFormat PluginOpenUrlInBrowser = System.Text.CompositeFormat.Parse(Properties.Resources.plugin_open_url_in_browser);
public FallbackOpenURLItem(SettingsManager settings)
: base(new OpenURLCommand(string.Empty, settings), string.Empty)
{
_executeItem = (OpenURLCommand)this.Command!;
Title = string.Empty;
_executeItem.Name = string.Empty;
Subtitle = string.Empty;
Icon = IconHelpers.FromRelativePath("Assets\\WebSearch.png");
}
public override void UpdateQuery(string query)
{
if (!IsValidUrl(query))
{
Title = string.Empty;
Subtitle = string.Empty;
return;
}
var success = Uri.TryCreate(query, UriKind.Absolute, out var uri);
// if url not contain schema, add http:// by default.
if (!success)
{
query = "https://" + query;
}
_executeItem.Url = query;
_executeItem.Name = string.IsNullOrEmpty(query) ? string.Empty : Properties.Resources.open_in_default_browser;
Title = string.Format(CultureInfo.CurrentCulture, PluginOpenURL, query);
Subtitle = string.Format(CultureInfo.CurrentCulture, PluginOpenUrlInBrowser, BrowserInfo.Name ?? BrowserInfo.MSEdgeName);
}
public static bool IsValidUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return false;
}
if (!url.Contains('.', StringComparison.OrdinalIgnoreCase))
{
// eg: 'com', 'org'. We don't think it's a valid url.
// This can simplify the logic of checking if the url is valid.
return false;
}
if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
{
return true;
}
if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
!url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) &&
!url.StartsWith("ftp://", StringComparison.OrdinalIgnoreCase) &&
!url.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
{
if (Uri.IsWellFormedUriString("https://" + url, UriKind.Absolute))
{
return true;
}
}
return false;
}
}

View File

@@ -195,6 +195,24 @@ namespace Microsoft.CmdPal.Ext.WebSearch.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Open &quot;{0}&quot;.
/// </summary>
public static string plugin_open_url {
get {
return ResourceManager.GetString("plugin_open_url", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open url in {0}.
/// </summary>
public static string plugin_open_url_in_browser {
get {
return ResourceManager.GetString("plugin_open_url_in_browser", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failed to open {0}..
/// </summary>

View File

@@ -163,6 +163,12 @@
<data name="plugin_open" xml:space="preserve">
<value>Search the web in {0}</value>
</data>
<data name="plugin_open_url" xml:space="preserve">
<value>Open "{0}"</value>
</data>
<data name="plugin_open_url_in_browser" xml:space="preserve">
<value>Open url in {0}</value>
</data>
<data name="plugin_search_failed" xml:space="preserve">
<value>Failed to open {0}.</value>
</data>

View File

@@ -14,6 +14,7 @@ public partial class WebSearchCommandsProvider : CommandProvider
{
private readonly SettingsManager _settingsManager = new();
private readonly FallbackExecuteSearchItem _fallbackItem;
private readonly FallbackOpenURLItem _openUrlFallbackItem;
public WebSearchCommandsProvider()
{
@@ -23,6 +24,7 @@ public partial class WebSearchCommandsProvider : CommandProvider
Settings = _settingsManager.Settings;
_fallbackItem = new FallbackExecuteSearchItem(_settingsManager);
_openUrlFallbackItem = new FallbackOpenURLItem(_settingsManager);
}
public override ICommandItem[] TopLevelCommands()
@@ -36,5 +38,5 @@ public partial class WebSearchCommandsProvider : CommandProvider
];
}
public override IFallbackCommandItem[]? FallbackCommands() => [_fallbackItem];
public override IFallbackCommandItem[]? FallbackCommands() => [_openUrlFallbackItem, _fallbackItem];
}

View File

@@ -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);
}
}

View File

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

View File

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

View File

@@ -152,7 +152,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
{
GenerateId();
UpdateAlias();
FetchAliasFromAliasManager();
UpdateHotkey();
UpdateTags();
}
@@ -163,24 +163,31 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
private void HandleChangeAlias()
{
SetAlias(Alias);
SetAlias();
Save();
}
public void SetAlias(CommandAlias? newAlias)
public void SetAlias()
{
_serviceProvider.GetService<AliasManager>()!.UpdateAlias(Id, newAlias);
UpdateAlias();
var commandAlias = Alias is null
? null
: new CommandAlias(Alias.Alias, Alias.CommandId, Alias.IsDirect);
_serviceProvider.GetService<AliasManager>()!.UpdateAlias(Id, commandAlias);
UpdateTags();
}
private void UpdateAlias()
private void FetchAliasFromAliasManager()
{
// Add tags for the alias, if we have one.
var aliases = _serviceProvider.GetService<AliasManager>();
if (aliases != null)
var am = _serviceProvider.GetService<AliasManager>();
if (am != null)
{
Alias = aliases.AliasFromId(Id);
var commandAlias = am.AliasFromId(Id);
if (commandAlias is not null)
{
// Decouple from the alias manager alias object
Alias = new CommandAlias(commandAlias.Alias, commandAlias.CommandId, commandAlias.IsDirect);
}
}
}

View File

@@ -54,7 +54,6 @@ public sealed partial class MainWindow : Window,
// Notification Area ("Tray") icon data
private NOTIFYICONDATAW? _trayIconData;
private bool _createdIcon;
private DestroyIconSafeHandle? _largeIcon;
private DesktopAcrylicController? _acrylicController;
@@ -99,7 +98,6 @@ public sealed partial class MainWindow : Window,
_hotkeyWndProc = HotKeyPrc;
var hotKeyPrcPointer = Marshal.GetFunctionPointerForDelegate(_hotkeyWndProc);
_originalWndProc = Marshal.GetDelegateForFunctionPointer<WNDPROC>(PInvoke.SetWindowLongPtr(_hwnd, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, hotKeyPrcPointer));
AddNotificationIcon();
// Load our settings, and then also wire up a settings changed handler
HotReloadSettings();
@@ -149,6 +147,7 @@ public sealed partial class MainWindow : Window,
var settings = App.Current.Services.GetService<SettingsModel>()!;
SetupHotkey(settings);
SetupTrayIcon(settings.ShowSystemTrayIcon);
// This will prevent our window from appearing in alt+tab or the taskbar.
// You'll _need_ to use the hotkey to summon it.
@@ -299,7 +298,7 @@ public sealed partial class MainWindow : Window,
var extensionService = serviceProvider.GetService<IExtensionService>()!;
extensionService.SignalStopExtensionsAsync();
RemoveNotificationIcon();
RemoveTrayIcon();
// WinUI bug is causing a crash on shutdown when FailFastOnErrors is set to true (#51773592).
// Workaround by turning it off before shutdown.
@@ -491,9 +490,9 @@ public sealed partial class MainWindow : Window,
// WM_WINDOWPOSCHANGING which is always received on explorer startup sequence.
case PInvoke.WM_WINDOWPOSCHANGING:
{
if (!_createdIcon)
if (_trayIconData == null)
{
AddNotificationIcon();
SetupTrayIcon();
}
}
@@ -505,7 +504,7 @@ public sealed partial class MainWindow : Window,
{
// Handle the case where explorer.exe restarts.
// Even if we created it before, do it again
AddNotificationIcon();
SetupTrayIcon();
}
else if (uMsg == WM_TRAY_ICON)
{
@@ -525,55 +524,60 @@ public sealed partial class MainWindow : Window,
return PInvoke.CallWindowProc(_originalWndProc, hwnd, uMsg, wParam, lParam);
}
private void AddNotificationIcon()
private void SetupTrayIcon(bool? showSystemTrayIcon = null)
{
// We only need to build the tray data once.
if (_trayIconData == null)
if (showSystemTrayIcon ?? App.Current.Services.GetService<SettingsModel>()!.ShowSystemTrayIcon)
{
// We need to stash this handle, so it doesn't clean itself up. If
// explorer restarts, we'll come back through here, and we don't
// really need to re-load the icon in that case. We can just use
// the handle from the first time.
_largeIcon = GetAppIconHandle();
_trayIconData = new NOTIFYICONDATAW()
// We only need to build the tray data once.
if (_trayIconData == null)
{
cbSize = (uint)Marshal.SizeOf(typeof(NOTIFYICONDATAW)),
hWnd = _hwnd,
uID = MY_NOTIFY_ID,
uFlags = NOTIFY_ICON_DATA_FLAGS.NIF_MESSAGE | NOTIFY_ICON_DATA_FLAGS.NIF_ICON | NOTIFY_ICON_DATA_FLAGS.NIF_TIP,
uCallbackMessage = WM_TRAY_ICON,
hIcon = (HICON)_largeIcon.DangerousGetHandle(),
szTip = RS_.GetString("AppStoreName"),
};
// We need to stash this handle, so it doesn't clean itself up. If
// explorer restarts, we'll come back through here, and we don't
// really need to re-load the icon in that case. We can just use
// the handle from the first time.
_largeIcon = GetAppIconHandle();
_trayIconData = new NOTIFYICONDATAW()
{
cbSize = (uint)Marshal.SizeOf(typeof(NOTIFYICONDATAW)),
hWnd = _hwnd,
uID = MY_NOTIFY_ID,
uFlags = NOTIFY_ICON_DATA_FLAGS.NIF_MESSAGE | NOTIFY_ICON_DATA_FLAGS.NIF_ICON | NOTIFY_ICON_DATA_FLAGS.NIF_TIP,
uCallbackMessage = WM_TRAY_ICON,
hIcon = (HICON)_largeIcon.DangerousGetHandle(),
szTip = RS_.GetString("AppStoreName"),
};
}
var d = (NOTIFYICONDATAW)_trayIconData;
// Add the notification icon
PInvoke.Shell_NotifyIcon(NOTIFY_ICON_MESSAGE.NIM_ADD, in d);
}
var d = (NOTIFYICONDATAW)_trayIconData;
// Add the notification icon
if (PInvoke.Shell_NotifyIcon(NOTIFY_ICON_MESSAGE.NIM_ADD, in d))
else
{
_createdIcon = true;
RemoveTrayIcon();
}
}
private void RemoveNotificationIcon()
private void RemoveTrayIcon()
{
if (_trayIconData != null && _createdIcon)
if (_trayIconData != null)
{
var d = (NOTIFYICONDATAW)_trayIconData;
if (PInvoke.Shell_NotifyIcon(NOTIFY_ICON_MESSAGE.NIM_DELETE, in d))
{
_createdIcon = false;
_trayIconData = null;
}
}
_largeIcon?.Close();
}
private DestroyIconSafeHandle GetAppIconHandle()
{
var exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
DestroyIconSafeHandle largeIcon;
DestroyIconSafeHandle smallIcon;
PInvoke.ExtractIconEx(exePath, 0, out largeIcon, out smallIcon, 1);
PInvoke.ExtractIconEx(exePath, 0, out largeIcon, out _, 1);
return largeIcon;
}
}

View File

@@ -73,12 +73,17 @@
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Private.Uri" />
<PackageReference Include="System.Text.Json" />
<!-- LOAD BEARING: GeneratePathProperty=true on BOTH the AC dependencies. Don't forget the AdaptiveCardsWorkaround below -->
<PackageReference Include="AdaptiveCards.ObjectModel.WinUI3" GeneratePathProperty="true" />
<PackageReference Include="AdaptiveCards.Rendering.WinUI3" GeneratePathProperty="True" />
<PackageReference Include="AdaptiveCards.Templating" />
<PackageReference Include="System.Text.RegularExpressions" />
</ItemGroup>
<!--

View File

@@ -68,6 +68,10 @@
<ToggleSwitch IsOn="{x:Bind viewModel.SingleClickActivates, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="Settings_GeneralPage_ShowSystemTrayIcon_SettingsCard" HeaderIcon="{ui:FontIcon Glyph=&#xE75B;}">
<ToggleSwitch IsOn="{x:Bind viewModel.ShowSystemTrayIcon, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Example 'About' section -->
<TextBlock x:Uid="AboutSettingsHeader" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />

View File

@@ -385,4 +385,10 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
<data name="BehaviorSettingsHeader.Text" xml:space="preserve">
<value>Behavior</value>
</data>
<data name="Settings_GeneralPage_ShowSystemTrayIcon_SettingsCard.Header" xml:space="preserve">
<value>Show system tray icon</value>
</data>
<data name="Settings_GeneralPage_ShowSystemTrayIcon_SettingsCard.Description" xml:space="preserve">
<value>Choose if Command Palette is visible in the system tray</value>
</data>
</root>

View File

@@ -40,7 +40,7 @@ Projects of interest are:
[Initial SDK Spec]: ./doc/initial-sdk-spec/initial-sdk-spec.md
[generic samples]: ./Exts/SamplePagesExtension
[real samples]: .Exts/ProcessMonitorExtension
[real samples]: ./Exts/ProcessMonitorExtension
[real extensions that we've "shipped" already]: https://github.com/zadjii/CmdPalExtensions/blob/main/src/extensions

View File

@@ -222,7 +222,7 @@ namespace ColorPicker.Helpers
public bool HandleEnterPressed()
{
if (!IsColorPickerVisible())
if (!_colorPickerShown)
{
return false;
}
@@ -233,14 +233,13 @@ namespace ColorPicker.Helpers
public bool HandleEscPressed()
{
if (!BlockEscapeKeyClosingColorPickerEditor)
if (!BlockEscapeKeyClosingColorPickerEditor
&& (_colorPickerShown || (_colorEditorWindow != null && _colorEditorWindow.IsActive)))
{
return EndUserSession();
}
else
{
return false;
}
return false;
}
internal void MoveCursor(int xOffset, int yOffset)

View File

@@ -70,17 +70,10 @@ namespace ColorPicker.Keyboard
var virtualCode = e.KeyboardData.VirtualCode;
// ESC pressed
if (virtualCode == KeyInterop.VirtualKeyFromKey(Key.Escape)
&& e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown
)
if (virtualCode == KeyInterop.VirtualKeyFromKey(Key.Escape) && e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown)
{
if (_appStateHandler.IsColorPickerVisible()
|| !AppStateHandler.BlockEscapeKeyClosingColorPickerEditor
)
{
e.Handled = _appStateHandler.EndUserSession();
return;
}
e.Handled = _appStateHandler.HandleEscPressed();
return;
}
if ((virtualCode == KeyInterop.VirtualKeyFromKey(Key.Space) || virtualCode == KeyInterop.VirtualKeyFromKey(Key.Enter)) && (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown))

View File

@@ -104,8 +104,10 @@ namespace ColorPicker.Mouse
var rect = new Rectangle((int)mousePosition.X, (int)mousePosition.Y, 1, 1);
using (var bmp = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb))
{
var g = Graphics.FromImage(bmp);
g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
using (var g = Graphics.FromImage(bmp)) // Ensure Graphics object is disposed
{
g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
}
return bmp.GetPixel(0, 0);
}

View File

@@ -20,6 +20,9 @@
<ItemGroup>
<PackageReference Include="Appium.WebDriver" />
<PackageReference Include="MSTest" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Private.Uri" />
<PackageReference Include="System.Text.RegularExpressions" />
</ItemGroup>
<ItemGroup>

View File

@@ -21,6 +21,9 @@
<PackageReference Include="Appium.WebDriver" />
<PackageReference Include="MSTest" />
<PackageReference Include="System.IO.Abstractions" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Private.Uri" />
<PackageReference Include="System.Text.RegularExpressions" />
</ItemGroup>
<ItemGroup>

View File

@@ -117,15 +117,15 @@ namespace EditorHelpers
}
if (shortcut.ctrlKey != ModifierKey::Disabled)
{
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetCtrlKey()).c_str()));
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetCtrlKey(ModifierKey::Both)).c_str()));
}
if (shortcut.altKey != ModifierKey::Disabled)
{
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetAltKey()).c_str()));
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetAltKey(ModifierKey::Both)).c_str()));
}
if (shortcut.shiftKey != ModifierKey::Disabled)
{
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetShiftKey()).c_str()));
keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(shortcut.GetShiftKey(ModifierKey::Both)).c_str()));
}
if (shortcut.actionKey != NULL)
{

View File

@@ -158,13 +158,13 @@ namespace KeyboardEventHandlers
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
{
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(targetShortcut.GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
Helpers::SetModifierKeyEvents(targetShortcut, ModifierKey::Disabled, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
Helpers::SetModifierKeyEvents(targetShortcut, Modifiers(), keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
// Dummy key is not required here since SetModifierKeyEvents will only add key-up events for the modifiers here, and the action key key-up is already sent before it
}
else
{
// Dummy key is not required here since SetModifierKeyEvents will only add key-down events for the modifiers here, and the action key key-down is already sent after it
Helpers::SetModifierKeyEvents(targetShortcut, ModifierKey::Disabled, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
Helpers::SetModifierKeyEvents(targetShortcut, Modifiers(), keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(targetShortcut.GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
}
}
@@ -371,11 +371,35 @@ namespace KeyboardEventHandlers
// Remember which win key was pressed initially
if (ii.GetVirtualKeyState(VK_RWIN))
{
it->second.winKeyInvoked = ModifierKey::Right;
it->second.modifierKeysInvoked.winKey = ModifierKey::Right;
}
else if (ii.GetVirtualKeyState(VK_LWIN))
{
it->second.winKeyInvoked = ModifierKey::Left;
it->second.modifierKeysInvoked.winKey = ModifierKey::Left;
}
if (ii.GetVirtualKeyState(VK_RCONTROL))
{
it->second.modifierKeysInvoked.ctrlKey = ModifierKey::Right;
}
else if (ii.GetVirtualKeyState(VK_LCONTROL))
{
it->second.modifierKeysInvoked.ctrlKey = ModifierKey::Left;
}
if (ii.GetVirtualKeyState(VK_RSHIFT))
{
it->second.modifierKeysInvoked.shiftKey = ModifierKey::Right;
}
else if (ii.GetVirtualKeyState(VK_LSHIFT))
{
it->second.modifierKeysInvoked.shiftKey = ModifierKey::Left;
}
if (ii.GetVirtualKeyState(VK_RMENU))
{
it->second.modifierKeysInvoked.altKey = ModifierKey::Right;
}
else if (ii.GetVirtualKeyState(VK_LMENU))
{
it->second.modifierKeysInvoked.altKey = ModifierKey::Left;
}
if (isRunProgram)
@@ -450,7 +474,7 @@ namespace KeyboardEventHandlers
{
// key down for all new shortcut keys except the common modifiers
keyEventList = std::vector<INPUT>{};
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.modifierKeysInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
}
else
@@ -460,15 +484,15 @@ namespace KeyboardEventHandlers
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
// Release original shortcut state (release in reverse order of shortcut to be accurate)
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
Helpers::SetModifierKeyEvents(it->first, it->second.modifierKeysInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
// Set new shortcut key down state
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.modifierKeysInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
}
// Modifier state reset might be required for this key depending on the shortcut's action and target modifiers - ex: Win+Caps -> Ctrl+A
if (it->first.GetCtrlKey() == NULL && it->first.GetAltKey() == NULL && it->first.GetShiftKey() == NULL)
if (it->first.GetCtrlKey(it->second.modifierKeysInvoked.ctrlKey) == NULL && it->first.GetAltKey(it->second.modifierKeysInvoked.altKey) == NULL && it->first.GetShiftKey(it->second.modifierKeysInvoked.shiftKey) == NULL)
{
Shortcut temp = std::get<Shortcut>(it->second.targetShortcut);
for (auto keys : temp.GetKeyCodes())
@@ -490,7 +514,7 @@ namespace KeyboardEventHandlers
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
// Release original shortcut state (release in reverse order of shortcut to be accurate)
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
Helpers::SetModifierKeyEvents(it->first, it->second.modifierKeysInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
// Set target key down state
if (std::get<DWORD>(it->second.targetShortcut) != CommonSharedConstants::VK_DISABLED)
@@ -499,7 +523,7 @@ namespace KeyboardEventHandlers
}
// Modifier state reset might be required for this key depending on the shortcut's action and target modifier - ex: Win+Caps -> Ctrl
if (it->first.GetCtrlKey() == NULL && it->first.GetAltKey() == NULL && it->first.GetShiftKey() == NULL)
if (it->first.GetCtrlKey(it->second.modifierKeysInvoked.ctrlKey) == NULL && it->first.GetAltKey(it->second.modifierKeysInvoked.altKey) == NULL && it->first.GetShiftKey(it->second.modifierKeysInvoked.shiftKey) == NULL)
{
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), data->lParam->vkCode);
}
@@ -512,7 +536,7 @@ namespace KeyboardEventHandlers
Helpers::SetDummyKeyEvent(keyEventList, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
// Release original shortcut state (release in reverse order of shortcut to be accurate)
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
Helpers::SetModifierKeyEvents(it->first, it->second.modifierKeysInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
Helpers::SetTextKeyEvents(keyEventList, remapping);
}
@@ -614,12 +638,12 @@ namespace KeyboardEventHandlers
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
}
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first, data->lParam->vkCode);
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.modifierKeysInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first, data->lParam->vkCode);
if (!isAltRightKeyInvoked)
{
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate its own key message
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut), data->lParam->vkCode);
Helpers::SetModifierKeyEvents(it->first, it->second.modifierKeysInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut), data->lParam->vkCode);
}
else
{
@@ -643,7 +667,7 @@ namespace KeyboardEventHandlers
if (!isAltRightKeyInvoked)
{
// Set original shortcut key down state except the action key and the released modifier since the original action key may or may not be held down. If it is held down it will generate its own key message
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, Shortcut(), data->lParam->vkCode);
Helpers::SetModifierKeyEvents(it->first, it->second.modifierKeysInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, Shortcut(), data->lParam->vkCode);
}
else
{
@@ -656,7 +680,7 @@ namespace KeyboardEventHandlers
// Reset the remap state
it->second.isShortcutInvoked = false;
it->second.winKeyInvoked = ModifierKey::Disabled;
it->second.modifierKeysInvoked.Reset();
it->second.isOriginalActionKeyPressed = false;
// If app specific shortcut has finished invoking, reset the target application
@@ -719,14 +743,14 @@ namespace KeyboardEventHandlers
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
// Release new shortcut state (release in reverse order of shortcut to be accurate)
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.modifierKeysInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
// Set old shortcut key down state
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
Helpers::SetModifierKeyEvents(it->first, it->second.modifierKeysInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
// Reset the remap state
it->second.isShortcutInvoked = false;
it->second.winKeyInvoked = ModifierKey::Disabled;
it->second.modifierKeysInvoked.Reset();
it->second.isOriginalActionKeyPressed = false;
// If app specific shortcut has finished invoking, reset the target application
@@ -763,7 +787,7 @@ namespace KeyboardEventHandlers
if (!isAltRightKeyInvoked)
{
// Set original shortcut key down state except the action key
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
Helpers::SetModifierKeyEvents(it->first, it->second.modifierKeysInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
}
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->V, press Shift+Win+A and release A, since Win will be pressed here we need to send a dummy event after it
@@ -773,7 +797,7 @@ namespace KeyboardEventHandlers
{
// Reset the remap state
it->second.isShortcutInvoked = false;
it->second.winKeyInvoked = ModifierKey::Disabled;
it->second.modifierKeysInvoked.Reset();
it->second.isOriginalActionKeyPressed = false;
}
@@ -795,7 +819,7 @@ namespace KeyboardEventHandlers
if (remapToShortcut)
{
// Modifier state reset might be required for this key depending on the target shortcut action key - ex: Ctrl+A -> Win+Caps
if (std::get<Shortcut>(it->second.targetShortcut).GetCtrlKey() == NULL && std::get<Shortcut>(it->second.targetShortcut).GetAltKey() == NULL && std::get<Shortcut>(it->second.targetShortcut).GetShiftKey() == NULL)
if (std::get<Shortcut>(it->second.targetShortcut).GetCtrlKey(it->second.modifierKeysInvoked.ctrlKey) == NULL && std::get<Shortcut>(it->second.targetShortcut).GetAltKey(it->second.modifierKeysInvoked.altKey) == NULL && std::get<Shortcut>(it->second.targetShortcut).GetShiftKey(it->second.modifierKeysInvoked.shiftKey) == NULL)
{
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, std::get<Shortcut>(it->second.targetShortcut).GetActionKey());
}
@@ -817,7 +841,7 @@ namespace KeyboardEventHandlers
if (remapToShortcut)
{
// Modifier state reset might be required for this key depending on the target shortcut action key - ex: Ctrl+A -> Win+Caps, Shift is pressed. System should not see Shift and Caps pressed together
if (std::get<Shortcut>(it->second.targetShortcut).GetCtrlKey() == NULL && std::get<Shortcut>(it->second.targetShortcut).GetAltKey() == NULL && std::get<Shortcut>(it->second.targetShortcut).GetShiftKey() == NULL)
if (std::get<Shortcut>(it->second.targetShortcut).GetCtrlKey(it->second.modifierKeysInvoked.ctrlKey) == NULL && std::get<Shortcut>(it->second.targetShortcut).GetAltKey(it->second.modifierKeysInvoked.altKey) == NULL && std::get<Shortcut>(it->second.targetShortcut).GetShiftKey(it->second.modifierKeysInvoked.shiftKey) == NULL)
{
ResetIfModifierKeyForLowerLevelKeyHandlers(ii, data->lParam->vkCode, std::get<Shortcut>(it->second.targetShortcut).GetActionKey());
}
@@ -837,7 +861,7 @@ namespace KeyboardEventHandlers
DWORD to = std::get<0>(newRemapping.targetShortcut);
if (!isAltRightKeyInvoked)
{
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
Helpers::SetModifierKeyEvents(from, it->second.modifierKeysInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
}
if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
{
@@ -851,7 +875,7 @@ namespace KeyboardEventHandlers
Shortcut to = std::get<Shortcut>(newRemapping.targetShortcut);
if (!isAltRightKeyInvoked)
{
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, to);
Helpers::SetModifierKeyEvents(from, it->second.modifierKeysInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, to);
}
if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
{
@@ -860,21 +884,11 @@ namespace KeyboardEventHandlers
}
if (!isAltRightKeyInvoked)
{
Helpers::SetModifierKeyEvents(to, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, from);
Helpers::SetModifierKeyEvents(to, it->second.modifierKeysInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, from);
}
Helpers::SetKeyEvent(keyEventList, INPUT_KEYBOARD, static_cast<WORD>(to.actionKey), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
newRemapping.isShortcutInvoked = true;
}
// Remember which win key was pressed initially
if (ii.GetVirtualKeyState(VK_RWIN))
{
newRemapping.winKeyInvoked = ModifierKey::Right;
}
else if (ii.GetVirtualKeyState(VK_LWIN))
{
newRemapping.winKeyInvoked = ModifierKey::Left;
}
}
else
{
@@ -888,10 +902,10 @@ namespace KeyboardEventHandlers
}
if (!isAltRightKeyInvoked)
{
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.modifierKeysInvoked, keyEventList, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
// Set old shortcut key down state
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
Helpers::SetModifierKeyEvents(it->first, it->second.modifierKeysInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, std::get<Shortcut>(it->second.targetShortcut));
}
// key down for original shortcut action key with shortcut flag so that we don't invoke the same shortcut remap again
@@ -910,7 +924,7 @@ namespace KeyboardEventHandlers
{
// Reset the remap state
it->second.isShortcutInvoked = false;
it->second.winKeyInvoked = ModifierKey::Disabled;
it->second.modifierKeysInvoked.Reset();
it->second.isOriginalActionKeyPressed = false;
}
@@ -960,7 +974,7 @@ namespace KeyboardEventHandlers
if (!isAltRightKeyInvoked)
{
// Set original shortcut key down state
Helpers::SetModifierKeyEvents(it->first, it->second.winKeyInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
Helpers::SetModifierKeyEvents(it->first, it->second.modifierKeysInvoked, keyEventList, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
}
// Send the original action key only if it is physically pressed. For remappings to keys other than disabled we already check earlier that it is not pressed in this scenario. For remap to disable
@@ -979,7 +993,7 @@ namespace KeyboardEventHandlers
{
// Reset the remap state
it->second.isShortcutInvoked = false;
it->second.winKeyInvoked = ModifierKey::Disabled;
it->second.modifierKeysInvoked.Reset();
it->second.isOriginalActionKeyPressed = false;
}

View File

@@ -145,15 +145,15 @@ std::wstring GetShortcutHumanReadableString(Shortcut const& shortcut, LayoutMap&
}
if (shortcut.ctrlKey != ModifierKey::Disabled)
{
humanReadableShortcut += keyboardMap.GetKeyName(shortcut.GetCtrlKey()) + L" + ";
humanReadableShortcut += keyboardMap.GetKeyName(shortcut.GetCtrlKey(ModifierKey::Both)) + L" + ";
}
if (shortcut.altKey != ModifierKey::Disabled)
{
humanReadableShortcut += keyboardMap.GetKeyName(shortcut.GetAltKey()) + L" + ";
humanReadableShortcut += keyboardMap.GetKeyName(shortcut.GetAltKey(ModifierKey::Both)) + L" + ";
}
if (shortcut.shiftKey != ModifierKey::Disabled)
{
humanReadableShortcut += keyboardMap.GetKeyName(shortcut.GetShiftKey()) + L" + ";
humanReadableShortcut += keyboardMap.GetKeyName(shortcut.GetShiftKey(ModifierKey::Both)) + L" + ";
}
if (shortcut.actionKey != NULL)
{

View File

@@ -262,27 +262,27 @@ namespace Helpers
}
// Function to set key events for modifier keys: When shortcutToCompare is passed (non-empty shortcut), then the key event is sent only if both shortcut's don't have the same modifier key. When keyToBeReleased is passed (non-NULL), then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const ModifierKey& winKeyInvoked, std::vector<INPUT>& keyEventArray, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare, const DWORD& keyToBeReleased)
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const Modifiers& modifiersKeys, std::vector<INPUT>& keyEventArray, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare, const DWORD& keyToBeReleased)
{
// If key down is to be sent, send in the order Win, Ctrl, Alt, Shift
if (isKeyDown)
{
// If shortcutToCompare is non-empty, then the key event is sent only if both shortcut's don't have the same modifier key. If keyToBeReleased is non-NULL, then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
if (shortcutToBeSent.GetWinKey(winKeyInvoked) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetWinKey(winKeyInvoked) != shortcutToCompare.GetWinKey(winKeyInvoked)) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckWinKey(keyToBeReleased)))
if (shortcutToBeSent.GetWinKey(modifiersKeys.winKey) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetWinKey(modifiersKeys.winKey) != shortcutToCompare.GetWinKey(modifiersKeys.winKey)) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckWinKey(keyToBeReleased)))
{
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetWinKey(winKeyInvoked)), 0, extraInfoFlag);
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetWinKey(modifiersKeys.winKey)), 0, extraInfoFlag);
}
if (shortcutToBeSent.GetCtrlKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey() != shortcutToCompare.GetCtrlKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
if (shortcutToBeSent.GetCtrlKey(modifiersKeys.ctrlKey) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey(modifiersKeys.ctrlKey) != shortcutToCompare.GetCtrlKey(modifiersKeys.ctrlKey)) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
{
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetCtrlKey()), 0, extraInfoFlag);
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetCtrlKey(modifiersKeys.ctrlKey)), 0, extraInfoFlag);
}
if (shortcutToBeSent.GetAltKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey() != shortcutToCompare.GetAltKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckAltKey(keyToBeReleased)))
if (shortcutToBeSent.GetAltKey(modifiersKeys.altKey) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey(modifiersKeys.altKey) != shortcutToCompare.GetAltKey(modifiersKeys.altKey)) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckAltKey(keyToBeReleased)))
{
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetAltKey()), 0, extraInfoFlag);
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetAltKey(modifiersKeys.altKey)), 0, extraInfoFlag);
}
if (shortcutToBeSent.GetShiftKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetShiftKey() != shortcutToCompare.GetShiftKey()) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckShiftKey(keyToBeReleased)))
if (shortcutToBeSent.GetShiftKey(modifiersKeys.shiftKey) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetShiftKey(modifiersKeys.shiftKey) != shortcutToCompare.GetShiftKey(modifiersKeys.shiftKey)) && (keyToBeReleased == NULL || !shortcutToBeSent.CheckShiftKey(keyToBeReleased)))
{
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetShiftKey()), 0, extraInfoFlag);
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetShiftKey(modifiersKeys.shiftKey)), 0, extraInfoFlag);
}
}
@@ -290,21 +290,21 @@ namespace Helpers
else
{
// If shortcutToCompare is non-empty, then the key event is sent only if both shortcut's don't have the same modifier key. If keyToBeReleased is non-NULL, then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
if (shortcutToBeSent.GetShiftKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetShiftKey() != shortcutToCompare.GetShiftKey() || shortcutToBeSent.CheckShiftKey(keyToBeReleased)))
if (shortcutToBeSent.GetShiftKey(modifiersKeys.shiftKey) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetShiftKey(modifiersKeys.shiftKey) != shortcutToCompare.GetShiftKey(modifiersKeys.shiftKey) || shortcutToBeSent.CheckShiftKey(keyToBeReleased)))
{
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetShiftKey()), KEYEVENTF_KEYUP, extraInfoFlag);
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetShiftKey(modifiersKeys.shiftKey)), KEYEVENTF_KEYUP, extraInfoFlag);
}
if (shortcutToBeSent.GetAltKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey() != shortcutToCompare.GetAltKey() || shortcutToBeSent.CheckAltKey(keyToBeReleased)))
if (shortcutToBeSent.GetAltKey(modifiersKeys.altKey) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetAltKey(modifiersKeys.altKey) != shortcutToCompare.GetAltKey(modifiersKeys.altKey) || shortcutToBeSent.CheckAltKey(keyToBeReleased)))
{
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetAltKey()), KEYEVENTF_KEYUP, extraInfoFlag);
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetAltKey(modifiersKeys.altKey)), KEYEVENTF_KEYUP, extraInfoFlag);
}
if (shortcutToBeSent.GetCtrlKey() != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey() != shortcutToCompare.GetCtrlKey() || shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
if (shortcutToBeSent.GetCtrlKey(modifiersKeys.ctrlKey) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetCtrlKey(modifiersKeys.ctrlKey) != shortcutToCompare.GetCtrlKey(modifiersKeys.ctrlKey) || shortcutToBeSent.CheckCtrlKey(keyToBeReleased)))
{
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetCtrlKey()), KEYEVENTF_KEYUP, extraInfoFlag);
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetCtrlKey(modifiersKeys.ctrlKey)), KEYEVENTF_KEYUP, extraInfoFlag);
}
if (shortcutToBeSent.GetWinKey(winKeyInvoked) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetWinKey(winKeyInvoked) != shortcutToCompare.GetWinKey(winKeyInvoked) || shortcutToBeSent.CheckWinKey(keyToBeReleased)))
if (shortcutToBeSent.GetWinKey(modifiersKeys.winKey) != NULL && (shortcutToCompare.IsEmpty() || shortcutToBeSent.GetWinKey(modifiersKeys.winKey) != shortcutToCompare.GetWinKey(modifiersKeys.winKey) || shortcutToBeSent.CheckWinKey(keyToBeReleased)))
{
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetWinKey(winKeyInvoked)), KEYEVENTF_KEYUP, extraInfoFlag);
Helpers::SetKeyEvent(keyEventArray, INPUT_KEYBOARD, static_cast<WORD>(shortcutToBeSent.GetWinKey(modifiersKeys.winKey)), KEYEVENTF_KEYUP, extraInfoFlag);
}
}
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include "Shortcut.h"
#include "RemapShortcut.h"
class LayoutMap;
@@ -47,7 +48,8 @@ namespace Helpers
std::wstring GetCurrentApplication(bool keepPath);
// Function to set key events for modifier keys: When shortcutToCompare is passed (non-empty shortcut), then the key event is sent only if both shortcut's don't have the same modifier key. When keyToBeReleased is passed (non-NULL), then the key event is sent if either the shortcuts don't have the same modifier or if the shortcutToBeSent's modifier matches the keyToBeReleased
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const ModifierKey& winKeyInvoked, std::vector<INPUT>& keyEventArray, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare = Shortcut(), const DWORD& keyToBeReleased = NULL);
void SetModifierKeyEvents(const Shortcut& shortcutToBeSent, const Modifiers& modifiersKeys, std::vector<INPUT>& keyEventArray, bool isKeyDown, ULONG_PTR extraInfoFlag, const Shortcut& shortcutToCompare = Shortcut(), const DWORD& keyToBeReleased = NULL);
// Function to filter the key codes for artificial key codes
int32_t FilterArtificialKeys(const int32_t& key);

View File

@@ -54,6 +54,7 @@
<ClInclude Include="InputInterface.h" />
<ClInclude Include="Helpers.h" />
<ClInclude Include="KeyboardManagerConstants.h" />
<ClInclude Include="Modifiers.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="RemapShortcut.h" />
<ClInclude Include="Shortcut.h" />

View File

@@ -65,6 +65,9 @@
<ClInclude Include="MappingConfiguration.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Modifiers.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -0,0 +1,26 @@
#pragma once
#include "ModifierKey.h"
#include <vector>
class Modifiers
{
public:
ModifierKey winKey = ModifierKey::Disabled;
ModifierKey ctrlKey = ModifierKey::Disabled;
ModifierKey altKey = ModifierKey::Disabled;
ModifierKey shiftKey = ModifierKey::Disabled;
void Reset()
{
winKey = ModifierKey::Disabled;
ctrlKey = ModifierKey::Disabled;
altKey = ModifierKey::Disabled;
shiftKey = ModifierKey::Disabled;
}
inline bool operator==(const Modifiers& other) const
{
return winKey == other.winKey && ctrlKey == other.ctrlKey && altKey == other.altKey && shiftKey == other.shiftKey;
}
};

View File

@@ -1,6 +1,8 @@
#pragma once
#include "Shortcut.h"
#include "Modifiers.h"
#include <variant>
#include <vector>
// This class stores all the variables associated with each shortcut remapping
class RemapShortcut
@@ -8,23 +10,24 @@ class RemapShortcut
public:
KeyShortcutTextUnion targetShortcut;
bool isShortcutInvoked;
ModifierKey winKeyInvoked;
Modifiers modifierKeysInvoked;
// This bool value is only required for remapping shortcuts to Disable
bool isOriginalActionKeyPressed;
RemapShortcut(const KeyShortcutTextUnion& sc) :
targetShortcut(sc), isShortcutInvoked(false), winKeyInvoked(ModifierKey::Disabled), isOriginalActionKeyPressed(false)
targetShortcut(sc), isShortcutInvoked(false), isOriginalActionKeyPressed(false)
{
}
RemapShortcut() :
targetShortcut(Shortcut()), isShortcutInvoked(false), winKeyInvoked(ModifierKey::Disabled), isOriginalActionKeyPressed(false)
targetShortcut(Shortcut()), isShortcutInvoked(false), isOriginalActionKeyPressed(false)
{
}
inline bool operator==(const RemapShortcut& sc) const
{
return targetShortcut == sc.targetShortcut && isShortcutInvoked == sc.isShortcutInvoked && winKeyInvoked == sc.winKeyInvoked;
return targetShortcut == sc.targetShortcut && isShortcutInvoked == sc.isShortcutInvoked && modifierKeysInvoked == sc.modifierKeysInvoked;
}
bool RemapToKey()

View File

@@ -185,7 +185,7 @@ DWORD Shortcut::GetWinKey(const ModifierKey& input) const
}
// Function to return the virtual key code of the ctrl key state expected in the shortcut. Return NULL if it is not a part of the shortcut
DWORD Shortcut::GetCtrlKey() const
DWORD Shortcut::GetCtrlKey(const ModifierKey& input) const
{
if (ctrlKey == ModifierKey::Disabled)
{
@@ -201,12 +201,20 @@ DWORD Shortcut::GetCtrlKey() const
}
else
{
if (input == ModifierKey::Right)
{
return VK_RCONTROL;
}
if (input == ModifierKey::Left)
{
return VK_LCONTROL;
}
return VK_CONTROL;
}
}
// Function to return the virtual key code of the alt key state expected in the shortcut. Return NULL if it is not a part of the shortcut
DWORD Shortcut::GetAltKey() const
DWORD Shortcut::GetAltKey(const ModifierKey& input) const
{
if (altKey == ModifierKey::Disabled)
{
@@ -220,6 +228,14 @@ DWORD Shortcut::GetAltKey() const
{
return VK_RMENU;
}
if (input == ModifierKey::Right)
{
return VK_RMENU;
}
else if (input == ModifierKey::Left || input == ModifierKey::Disabled)
{
return VK_LMENU;
}
else
{
return VK_MENU;
@@ -227,7 +243,7 @@ DWORD Shortcut::GetAltKey() const
}
// Function to return the virtual key code of the shift key state expected in the shortcut. Return NULL if it is not a part of the shortcut
DWORD Shortcut::GetShiftKey() const
DWORD Shortcut::GetShiftKey(const ModifierKey& input) const
{
if (shiftKey == ModifierKey::Disabled)
{
@@ -243,6 +259,14 @@ DWORD Shortcut::GetShiftKey() const
}
else
{
if (input == ModifierKey::Right)
{
return VK_RSHIFT;
}
if (input == ModifierKey::Left)
{
return VK_LSHIFT;
}
return VK_SHIFT;
}
}
@@ -493,15 +517,15 @@ winrt::hstring Shortcut::ToHstringVK() const
}
if (ctrlKey != ModifierKey::Disabled)
{
output = output + winrt::to_hstring(static_cast<unsigned int>(GetCtrlKey())) + winrt::to_hstring(L";");
output = output + winrt::to_hstring(static_cast<unsigned int>(GetCtrlKey(ModifierKey::Both))) + winrt::to_hstring(L";");
}
if (altKey != ModifierKey::Disabled)
{
output = output + winrt::to_hstring(static_cast<unsigned int>(GetAltKey())) + winrt::to_hstring(L";");
output = output + winrt::to_hstring(static_cast<unsigned int>(GetAltKey(ModifierKey::Both))) + winrt::to_hstring(L";");
}
if (shiftKey != ModifierKey::Disabled)
{
output = output + winrt::to_hstring(static_cast<unsigned int>(GetShiftKey())) + winrt::to_hstring(L";");
output = output + winrt::to_hstring(static_cast<unsigned int>(GetShiftKey(ModifierKey::Both))) + winrt::to_hstring(L";");
}
if (actionKey != NULL)
{
@@ -531,15 +555,15 @@ std::vector<DWORD> Shortcut::GetKeyCodes()
}
if (ctrlKey != ModifierKey::Disabled)
{
keys.push_back(GetCtrlKey());
keys.push_back(GetCtrlKey(ModifierKey::Both));
}
if (altKey != ModifierKey::Disabled)
{
keys.push_back(GetAltKey());
keys.push_back(GetAltKey(ModifierKey::Both));
}
if (shiftKey != ModifierKey::Disabled)
{
keys.push_back(GetShiftKey());
keys.push_back(GetShiftKey(ModifierKey::Both));
}
if (actionKey != NULL)
{

View File

@@ -4,7 +4,6 @@
#include <compare>
#include <tuple>
#include <variant>
namespace KeyboardManagerInput
{
class InputInterface;
@@ -142,13 +141,13 @@ public:
DWORD GetWinKey(const ModifierKey& input) const;
// Function to return the virtual key code of the ctrl key state expected in the shortcut. Return NULL if it is not a part of the shortcut
DWORD GetCtrlKey() const;
DWORD GetCtrlKey(const ModifierKey& input) const;
// Function to return the virtual key code of the alt key state expected in the shortcut. Return NULL if it is not a part of the shortcut
DWORD GetAltKey() const;
DWORD GetAltKey(const ModifierKey& input) const;
// Function to return the virtual key code of the shift key state expected in the shortcut. Return NULL if it is not a part of the shortcut
DWORD GetShiftKey() const;
DWORD GetShiftKey(const ModifierKey& input) const;
// Function to check if the input key matches the win key expected in the shortcut
bool CheckWinKey(const DWORD input) const;

View File

@@ -82,7 +82,7 @@ namespace Microsoft.Plugin.Program.Programs
public ApplicationType AppType { get; set; }
// Wrappers for File Operations
public static IFileVersionInfoWrapper FileVersionInfoWrapper { get; set; } = new FileVersionInfoWrapper();
public static IFileVersionInfoWrapper FileVersionInfoWrapper { get; set; } = new Wox.Infrastructure.FileSystemHelper.FileVersionInfoWrapper();
public static IFile FileWrapper { get; set; } = new FileSystem().File;

View File

@@ -325,7 +325,7 @@ namespace PowerAccent.Core
LetterKey.VK_H => new[] { "ĥ" },
LetterKey.VK_J => new[] { "ĵ" },
LetterKey.VK_S => new[] { "ŝ" },
LetterKey.VK_U => new[] { "ǔ" },
LetterKey.VK_U => new[] { "ŭ" },
_ => Array.Empty<string>(),
};
}

View File

@@ -16,6 +16,9 @@
<PackageReference Include="Moq" />
<PackageReference Include="MSTest" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Private.Uri" />
<PackageReference Include="System.Text.RegularExpressions" />
</ItemGroup>
<ItemGroup>

View File

@@ -60,6 +60,9 @@
<PackageReference Include="CommunityToolkit.WinUI.Extensions" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Markdown" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Private.Uri" />
<PackageReference Include="System.Text.RegularExpressions" />
<PackageReference Include="WinUIEx" />
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
<PackageReference Include="MessagePack" />
@@ -75,6 +78,8 @@
<PackageReference Include="Microsoft.Web.WebView2" />
<!-- HACK: CmdPal uses CommunityToolkit.Common directly. Align the version. -->
<PackageReference Include="CommunityToolkit.Common" />
<!-- HACK: MWB and Advanced Paste. Align the version. got flagged when https://github.com/microsoft/PowerToys/pull/38779 was done -->
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<!-- Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging

View File

@@ -31,7 +31,6 @@ namespace Microsoft.PowerToys.Settings.UI
private WindowId _windowId;
private IntPtr _hWnd;
private AppWindow _appWindow;
private WindowMessageMonitor _msgMonitor;
private bool disposedValue;
public OobeWindow(PowerToysModules initialModule)
@@ -46,10 +45,6 @@ namespace Microsoft.PowerToys.Settings.UI
_appWindow = AppWindow.GetFromWindowId(_windowId);
this.Activated += Window_Activated_SetIcon;
OverlappedPresenter presenter = _appWindow.Presenter as OverlappedPresenter;
presenter.IsMinimizable = false;
presenter.IsMaximizable = false;
var dpi = NativeMethods.GetDpiForWindow(_hWnd);
_currentDPI = dpi;
float scalingFactor = (float)dpi / DefaultDPI;
@@ -63,18 +58,6 @@ namespace Microsoft.PowerToys.Settings.UI
this.initialModule = initialModule;
_msgMonitor = new WindowMessageMonitor(this);
_msgMonitor.WindowMessageReceived += (_, e) =>
{
const int WM_NCLBUTTONDBLCLK = 0x00A3;
if (e.Message.MessageId == WM_NCLBUTTONDBLCLK)
{
// Disable double click on title bar to maximize window
e.Result = 0;
e.Handled = true;
}
};
this.SizeChanged += OobeWindow_SizeChanged;
var loader = Helpers.ResourceLoaderInstance.ResourceLoader;
@@ -154,8 +137,6 @@ namespace Microsoft.PowerToys.Settings.UI
{
if (!disposedValue)
{
_msgMonitor?.Dispose();
disposedValue = true;
}
}

View File

@@ -458,7 +458,7 @@
<controls:SettingsPageControl.PrimaryLinks>
<controls:PageLink x:Uid="GeneralPage_Documentation" Link="https://aka.ms/PowerToysOverview" />
<controls:PageLink x:Uid="General_Repository" Link="https://aka.ms/powertoys" />
<controls:PageLink x:Uid="GeneralPage_ReportAbug" Link="https://aka.ms/powerToysReportBug" />
<controls:PageLink x:Uid="GeneralPage_ReportAbug" Link="{x:Bind ViewModel.ReportBugLink, Mode=OneWay}" />
<controls:PageLink x:Uid="GeneralPage_RequestAFeature_URL" Link="https://aka.ms/powerToysRequestFeature" />
</controls:SettingsPageControl.PrimaryLinks>
<controls:SettingsPageControl.SecondaryLinks>

View File

@@ -84,6 +84,8 @@ namespace Microsoft.PowerToys.Settings.UI.Views
DataContext = ViewModel;
ViewModel.InitializeReportBugLink();
doRefreshBackupRestoreStatus(100);
}

View File

@@ -9,6 +9,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json;
@@ -25,11 +26,19 @@ using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
using Microsoft.PowerToys.Settings.UI.SerializationContext;
using Microsoft.PowerToys.Telemetry;
using Microsoft.Win32;
using Windows.System.Profile;
namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
public partial class GeneralViewModel : Observable
{
public enum InstallScope
{
PerMachine = 0,
PerUser,
}
private GeneralSettings GeneralSettingsConfig { get; set; }
private UpdatingSettings UpdatingSettingsConfig { get; set; }
@@ -72,6 +81,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private SettingsBackupAndRestoreUtils settingsBackupAndRestoreUtils = SettingsBackupAndRestoreUtils.Instance;
private const string InstallScopeRegKey = @"Software\Classes\powertoys\";
public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository, string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "", Action dispatcherAction = null, Action hideBackupAndRestoreMessageAreaAction = null, Action<int> doBackupAndRestoreDryRun = null, Func<Task<string>> pickSingleFolderDialog = null, Windows.ApplicationModel.Resources.ResourceLoader resourceLoader = null)
{
CheckForUpdatesEventHandler = new ButtonClickCommand(CheckForUpdatesClick);
@@ -256,6 +267,73 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private int _initLanguagesIndex;
private bool _languageChanged;
private string reportBugLink;
// Gets or sets a value indicating whether run powertoys on start-up.
public string ReportBugLink
{
get => reportBugLink;
set
{
reportBugLink = value;
OnPropertyChanged(nameof(ReportBugLink));
}
}
public void InitializeReportBugLink()
{
var version = GetPowerToysVersion();
string isElevatedString = "PowerToys is running " + (IsElevated ? "as admin (elevated)" : "as user (non-elevated)");
string installScope = GetCurrentInstallScope() == InstallScope.PerMachine ? "per machine (system)" : "per user";
var info = $"OS Version: {GetOSVersion()} \n.NET Version: {GetDotNetVersion()}\n{isElevatedString}\nInstall scope: {installScope}\nOperating System Language: {CultureInfo.InstalledUICulture.DisplayName}\nSystem locale: {CultureInfo.InstalledUICulture.Name}";
var gitHubURL = "https://github.com/microsoft/PowerToys/issues/new?template=bug_report.yml&labels=Issue-Bug%2CTriage-Needed" +
"&version=" + version + "&additionalInfo=" + System.Web.HttpUtility.UrlEncode(info);
ReportBugLink = gitHubURL;
}
private string GetPowerToysVersion()
{
return Helper.GetProductVersion().TrimStart('v');
}
private string GetOSVersion()
{
return Environment.OSVersion.VersionString;
}
public static string GetDotNetVersion()
{
return $".NET {Environment.Version}";
}
public static InstallScope GetCurrentInstallScope()
{
// Check HKLM first
if (Registry.LocalMachine.OpenSubKey(InstallScopeRegKey) != null)
{
return InstallScope.PerMachine;
}
// If not found, check HKCU
var userKey = Registry.CurrentUser.OpenSubKey(InstallScopeRegKey);
if (userKey != null)
{
var installScope = userKey.GetValue("InstallScope") as string;
userKey.Close();
if (!string.IsNullOrEmpty(installScope) && installScope.Contains("perUser"))
{
return InstallScope.PerUser;
}
}
return InstallScope.PerMachine; // Default if no specific registry key found
}
// Gets or sets a value indicating whether run powertoys on start-up.
public bool Startup
{