Compare commits

...

17 Commits

Author SHA1 Message Date
Gordon Lam (SH)
3c1241aa6f Make Common.Dotnet.CsWinRT.props includes Common.SelfContained.props 2025-04-09 12:15:38 +08:00
Kai Tao
6f43aac26a [CmdPal] [Install] do not install dependency if already satisfied. (#38531)
* do not install dependency if already satisfied.
* self contain winappsdk
2025-04-09 07:16:08 +08:00
Mike Griese
d7e826d2ac Fix the WinGet missing / Admin crash (#38493)
This is a fix for a pair of related crashes. 

Basically, we'd crash on startup if we failed to initialize WinGet. This could happen in two different places:
* If WinGet wasn't installed, then we'd explode, cause obviously we can't call its APIs
* If we're running as Admin, we won't be able to instantiate it's COM server. 

Regardless of how it happens, I've defaulted us to just _not enabling the winget built-in_. That's the simplest solution here. 

As I was helpfully reminded, there's also an elevated WindowsPackageManagerFactory we could use too - though, that wouldn't solve the case of "winget isn't installed"

Closes #38460
Closes #38440 (most likely)
2025-04-08 04:22:29 -07:00
Clint Rutkas
9e8754a592 Fixing settings for mouse pointer for pt run and cmdpal (#38649)
In CmdPal and PT Run, if you currently try to go to mouse pointer, it fails.  This looks to be due to capitalization in the command.  This can be validated via run dialog also.

shifting to lowercase fixes the bug.

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

- [x] **Closes:** #38223
2025-04-08 04:21:03 -07:00
moooyo
49687251d3 [cmdpal] Simplify time And Date extension code to make it easier to understand (#38075)
Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
2025-04-08 16:19:13 +08:00
DanielEScherzer
f72ccd12fd doc/devdocs/UITests.md: add missing period [skip ci] (#38605) 2025-04-08 15:29:18 +08:00
Clint Rutkas
4b44858a48 Adding in Hawker for CmdPal to Readme (#38647)
Update README.md

We missed Hawker!!!
2025-04-07 18:02:30 -07:00
Kayla Cinnamon
53ae118e72 Update version placeholder in bug_report.yml (#38504) 2025-04-07 17:06:34 -07:00
Clint Rutkas
31df702704 Updating the community md for recent adjustments (#38366)
* Update COMMUNITY.md

Adjusting team

* Update names.txt

* Update expect.txt
2025-04-07 12:42:56 -07:00
Clint Rutkas
ea2542b235 Adding Pedro for his hard 3D file work (#38599)
Adding Pedro
2025-04-07 12:42:38 -07:00
Davide Giacometti
c6776d0d45 [CmdPal] Fix Up/Down keyboard navigation + continuous navigation (#38499)
## Summary of the Pull Request

Fix #38337 and implement continuous navigation like PT Run v1

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

- [x] **Closes:** #38337
2025-04-03 06:47:23 -05:00
Mike Griese
d48286a3eb Scale the toast window for DPI (#38198)
Ah of course, AppWindow.Resize doesn't use DIPs. Why would it? It's not like literally everything else in XAML does.

Related to half of https://github.com/zadjii-msft/PowerToys/issues/508
2025-04-03 06:44:10 -05:00
Jaime Bernardo
7a5b25cd3e [Settings]Fix blank icon in the taskbar (#38259) 2025-04-02 17:59:46 -07:00
Clint Rutkas
1eccbc3021 WinGet installer fix (#38422)
Update package.h
2025-04-01 16:21:15 -07:00
Heiko
ce620e427f [PT Run > Time and Date plugin] Custom formats and other improvements (#37743)
* add settings definition

* fix typos and improve settings

* make spell checker happy

* new icon type error

* first code to handle custom formats

* support parsing of new formats

* spelling and typos

* comment fix

* spell check

* start implement custom format results

* last changes

* finish implementation

* spell checker

* settings name

* add missing format

* reorder settings

* dev docs

* change ELF to EAB

* update dev docs

* last changes

* test cases

* fix typos

* fix typo

* port changes

* fixes

* changes

* fixes

* leap year support

* days in month

* tests

* comment

* fix comment
2025-04-01 21:31:35 +08:00
Hao Liu
721c84d3a6 Install .NET 9 for MSStore release (#38361)
fix dotnet 9
2025-04-01 10:08:25 +08:00
Hao Liu
96ba445cfa 0.90 changelog (#38072)
* First draft. Some PRs are still under review.

* update wording

* remove the Svg thumbnail since it has been reverted

* update cmdpal

* add cmdpal

* clear old hashes

* address comments

* Update README.md

Co-authored-by: Jay <65828559+Jay-o-Way@users.noreply.github.com>

* address more comments

* Update README.md

Co-authored-by: Mike Griese <migrie@microsoft.com>

* Add Command Palette gif to README

* upload gif of cmdpal

* Update README.md

Co-authored-by: Mike Griese <migrie@microsoft.com>

* Address comments

Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>

* Update README.md

Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>

* Update CmdPal description

Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>

* Remove extra spacing

Co-authored-by: PesBandi <127593627+PesBandi@users.noreply.github.com>

* update hash

* update gif with new icon

---------

Co-authored-by: Jay <65828559+Jay-o-Way@users.noreply.github.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>
Co-authored-by: PesBandi <127593627+PesBandi@users.noreply.github.com>
2025-03-31 16:09:26 -07:00
74 changed files with 1327 additions and 286 deletions

View File

@@ -11,7 +11,7 @@ body:
- type: input
attributes:
label: Microsoft PowerToys version
placeholder: 0.70.0
placeholder: X.XX.X
description: Hover over system tray icon or look at Settings
validations:
required: true

View File

@@ -110,6 +110,7 @@ Lambson
Laute
laviusmotileng
Leilei
Loewen
Luecking
Mahalingam
Markovic

View File

@@ -15,6 +15,7 @@ ACTIVATEAPP
activationaction
ACVS
adaptivecards
ADate
ADDSTRING
ADDUNDORECORD
ADifferent
@@ -199,8 +200,7 @@ CLIPCHILDREN
CLIPSIBLINGS
closesocket
CLSCTX
CLSIDs
Clsids
clsids
Clusion
cmder
CMDNOTFOUNDMODULEINTERFACE
@@ -417,6 +417,7 @@ DWORDLONG
dworigin
dwrite
dxgi
eab
easeofaccess
ecount
Edid
@@ -466,6 +467,7 @@ EXAND
EXCLUDEFROMCAPTURE
executionpolicy
exename
exf
EXITSIZEMOVE
exlist
EXPCMDFLAGS
@@ -898,6 +900,7 @@ MARKDOWNPREVIEWHANDLERCPP
MAXIMIZEBOX
MAXSHORTCUTSIZE
maxversiontested
mber
MBM
MBR
MDICHILD
@@ -1779,6 +1782,8 @@ USRDLL
UType
uuidv
uwp
ums
uxt
uxtheme
vabdq
validmodulename
@@ -1859,10 +1864,10 @@ webbrowsers
webpage
websites
wekyb
wft
wgpocpl
WHEREID
Wholegrain
WIC
wic
wifi
wil
@@ -1919,6 +1924,7 @@ WNDCLASSEXW
WNDCLASSW
WNDPROC
wnode
wom
WORKSPACESEDITOR
WORKSPACESLAUNCHER
WORKSPACESSNAPSHOTTOOL
@@ -1990,4 +1996,4 @@ zoomit
ZOOMITX
ZXk
ZXNs
zzz
zzz

View File

@@ -39,6 +39,11 @@ jobs:
echo powerToysInstallerX64Url=$(jq -n "$powerToysSetup" | jq -r '[.[]|select(.name | contains("x64"))][0].browser_download_url') >> $GITHUB_OUTPUT
echo powerToysInstallerArm64Url=$(jq -n "$powerToysSetup" | jq -r '[.[]|select(.name | contains("arm64"))][0].browser_download_url') >> $GITHUB_OUTPUT
- name: Setup .NET 9.0
uses: actions/setup-dotnet@v3
with:
dotnet-version: '9.0.x'
- uses: microsoft/setup-msstore-cli@v1
- name: Fetch Store Credential

View File

@@ -16,7 +16,7 @@ Christian contributed New+ utility
CleanCodeDeveloper helped do massive amounts of code stability and image resizer work.
### [@plante-msft](https://github.com/plante-msft) - Connor Plante
Connor was the creator of Workspaces and helped create PowerToys Run v2
Connor was the creator of Workspaces and helped create Command Palette (PowerToys Run v2)
### [@damienleroy](https://github.com/damienleroy) - [Damien Leroy](https://www.linkedin.com/in/Damien-Leroy-b2734416a/)
Damien has helped out by developing and contributing the Quick Accent utility.
@@ -46,7 +46,7 @@ Jeff added in multiple new features into Keyboard manager, such as key chord sup
Joe has helped triaging, discussing, issues as well as fixing bugs and building features for Text Extractor.
### [@joadoumie](https://github.com/joadoumie) - Jordi Adoumie
Jordi helped innovate amazing new features into Advanced Paste and helped create PowerToys Run v2
Jordi helped innovate amazing new features into Advanced Paste and helped create Command Palette (PowerToys Run v2)
### [@jsoref](https://github.com/jsoref) - [Josh Soref](https://check-spelling.dev/)
Helping keep our spelling correct :)
@@ -57,6 +57,9 @@ Color Picker is from Martin.
### [@mikeclayton](https://github.com/mikeclayton) - [Michael Clayton](https://michael-clayton.com)
Michael contributed the [initial version](https://github.com/microsoft/PowerToys/issues/23216) of the Mouse Jump tool and [a number of updates](https://github.com/microsoft/PowerToys/pulls?q=is%3Apr+author%3Amikeclayton) based on his FancyMouse utility.
### [@pedrolamas](https://github.com/pedrolamas/) - Pedro Lamas
Pedro helped create the thumbnail and File Explorer previewers for 3D files like STL and GCode. If you like 3D printing, these are very helpful.
### [@PesBandi](https://github.com/PesBandi/) - PesBandi
PesBandi has helped do massive amounts of Quick Accent and bug fixes.
@@ -184,15 +187,10 @@ ZoomIt source code was originally implemented by [Sysinternals](https://sysinter
- [@crutkas](https://github.com/crutkas/) - Clint Rutkas - Lead
- [@cinnamon-msft](https://github.com/cinnamon-msft) - Kayla Cinnamon - Lead
- [@nguyen-dows](https://github.com/nguyen-dows) - Christopher Nguyen - Product Manager
- [@jaimecbernardo](https://github.com/jaimecbernardo) - Jaime Bernardo - Dev lead
- [@craigloewen-msft](https://github.com/craigloewen-msft) - Craig Loewen - 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
- [@drawbyperpetual](https://github.com/drawbyperpetual) - Anirudha Shankar - Dev
- [@mantaionut](https://github.com/mantaionut) - Ionut Manta - Dev
- [@donlaci](https://github.com/donlaci) - Laszlo Nemeth - Dev
- [@SeraphimaZykova](https://github.com/SeraphimaZykova) - Seraphima Zykova - Dev
- [@stefansjfw](https://github.com/stefansjfw) - Stefan Markovic - Dev
- [@lei9444](https://github.com/lei9444) - Leilei Zhang - Dev
- [@shuaiyuanxx](https://github.com/shuaiyuanxx) - Shawn Yuan - Dev
- [@moooyo](https://github.com/moooyo) - Yu Leng - Dev
@@ -206,7 +204,7 @@ ZoomIt source code was originally implemented by [Sysinternals](https://sysinter
- [@wang563681252](https://github.com/wang563681252) - Zhaopeng Wang - Dev
- [@vanzue](https://github.com/vanzue) - Kai Tao - Dev
# Former PowerToys core team members
## Former PowerToys core team members
- [@indierawk2k2](https://github.com/indierawk2k2) - Mike Harsh - Product Manager
- [@ethanfangg](https://github.com/ethanfangg) - Ethan Fang - Product Manager
@@ -219,3 +217,9 @@ ZoomIt source code was originally implemented by [Sysinternals](https://sysinter
- [@taras-janea](https://github.com/taras-janea) - Taras Sich - Dev
- [@yuyoyuppe](https://github.com/yuyoyuppe) - Andrey Nekrasov - Dev
- [@gokcekantarci](https://github.com/gokcekantarci) - Gokce Kantarci - Dev
- [@drawbyperpetual](https://github.com/drawbyperpetual) - Anirudha Shankar - Dev
- [@mantaionut](https://github.com/mantaionut) - Ionut Manta - Dev
- [@donlaci](https://github.com/donlaci) - Laszlo Nemeth - Dev
- [@SeraphimaZykova](https://github.com/SeraphimaZykova) - Seraphima Zykova - Dev
- [@stefansjfw](https://github.com/stefansjfw) - Stefan Markovic - Dev
- [@jaimecbernardo](https://github.com/jaimecbernardo) - Jaime Bernardo - Dev lead

148
README.md
View File

@@ -11,14 +11,15 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
| | Current utilities: | |
|--------------|--------------------|--------------|
| [Advanced Paste](https://aka.ms/PowerToysOverview_AdvancedPaste) | [Always on Top](https://aka.ms/PowerToysOverview_AoT) | [PowerToys Awake](https://aka.ms/PowerToysOverview_Awake) |
| [Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) |
| [Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) | [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) |
| [File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) |
| [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) |
| [New+](https://aka.ms/PowerToysOverview_NewPlus) | [Peek](https://aka.ms/PowerToysOverview_Peek) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) |
| [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) |
| [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
| [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) | [ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) |
| [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | [Command Palette](https://aka.ms/PowerToysOverview_CmdPal) |
| [Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
| [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) |
| [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) |
| [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [New+](https://aka.ms/PowerToysOverview_NewPlus) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) |
| [Peek](https://aka.ms/PowerToysOverview_Peek) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) |
| [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) |
| [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) |
| [ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) |
## Installing and running Microsoft PowerToys
@@ -34,19 +35,19 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
Go to the [Microsoft PowerToys GitHub releases page][github-release-link] and click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user.
<!-- items that need to be updated release to release -->
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.90%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.89%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.89.0/PowerToysUserSetup-0.89.0-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.89.0/PowerToysUserSetup-0.89.0-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.89.0/PowerToysSetup-0.89.0-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.89.0/PowerToysSetup-0.89.0-arm64.exe
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.91%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.90%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.90.0/PowerToysUserSetup-0.90.0-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.90.0/PowerToysUserSetup-0.90.0-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.90.0/PowerToysSetup-0.90.0-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.90.0/PowerToysSetup-0.90.0-arm64.exe
| Description | Filename | sha256 hash |
|----------------|----------|-------------|
| Per user - x64 | [PowerToysUserSetup-0.89.0-x64.exe][ptUserX64] | B4F130CC96F321024A257499247F6FF6DA56612215ED3882E868AAE26C689E33 |
| Per user - ARM64 | [PowerToysUserSetup-0.89.0-arm64.exe][ptUserArm64] | F69B00F4E520EB09FA0D1D1669E21910C5225FE7A2EEDC0FA7C283B201A5F9C6 |
| Machine wide - x64 | [PowerToysSetup-0.89.0-x64.exe][ptMachineX64] | E18AC8F9023E341CF7DAD35367FB9DDDB6565D83D8155DBCDDB40AE8A24AE731 |
| Machine wide - ARM64 | [PowerToysSetup-0.89.0-arm64.exe][ptMachineArm64] | 17DEADEC601D6061D7AF4F487595CC36D9191813003CC2ECE381017F0EC71FBB |
| Per user - x64 | [PowerToysUserSetup-0.90.0-x64.exe][ptUserX64] | 2A6036F5B2D454084E55816C306E1E57EF1D14C916691CBDA42B469797605CE0 |
| Per user - ARM64 | [PowerToysUserSetup-0.90.0-arm64.exe][ptUserArm64] | AB2E4DC87A9D764BE897C5170E2890E174C89CA912A1916FA3AE1E427536EA4A |
| Machine wide - x64 | [PowerToysSetup-0.90.0-x64.exe][ptMachineX64] | 12801C44F43D0CC61E90DF1EFDC40E4F3C88341E0199D5B20791042D9B173DCF |
| Machine wide - ARM64 | [PowerToysSetup-0.90.0-arm64.exe][ptMachineArm64] | 2998007C8FCD7BD2770767C6502AAA2CC75B85EC30DE62986EC7005EB0014EDB |
This is our preferred method.
@@ -92,102 +93,95 @@ For guidance on developing for PowerToys, please read the [developer docs](/doc/
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
### 0.89 - February 2025 Update
### 0.90 - March 2025 Update
In this release, we focused on new features, stability, accessibility and automation.
In this release, we focused on new features, stability, and automation.
**✨Highlights**
- Enhanced Advanced Paste by adding media transcoding support to convert different video and audio file formats! Thanks [@snickler](https://github.com/snickler) for your help!
- Fixed crashes when loading thumbnails after the .NET 9 update and resolved PowerLauncher.exe blocking other MSI installers from creating shortcuts!
- Fixed accessibility issues across FancyZones, Image Resizer, and Settings to improve screen reader support and clarity!
- Enhanced UI automation framework across modules and added new tests to cover manual checks, with more improvements coming!
![Gif for Command Palette](doc/images/overview/CmdPal_Hero.gif)
### General
- New module: Command Palette ("CmdPal") - Created as the evolution of PowerToys Run with extensibility at the forefront, Command Palette is a quick launcher with a richer display and additional capabilities without sacrificing performance, allowing you to start anything with the shortcut **Win+Alt+Space**! Thanks [@zadjii-msft](https://github.com/zadjii-msft), [@niels9001](https://github.com/niels9001), [@michael-hawker](https://github.com/michael-hawker), [@joadoumie](https://github.com/joadoumie), [@plante-msft](https://github.com/plante-msft), [@ethanfangg](https://github.com/ethanfangg) and [@krschau](https://github.com/krschau)!
- Enhanced the Color Picker by switching from WPF UI to .NET WPF, resulting in improved themes and visual consistency across different modes. Thanks [@mantaionut](https://github.com/mantaionut)! Thanks [@Jay-o-Way](https://github.com/Jay-o-Way) and [@niels9001](https://github.com/niels9001) for helping with the review!
- Added the ability to delete files directly from Peek, enhancing file management efficiency. Thanks [@daverayment](https://github.com/daverayment) and thanks [@htcfreek](https://github.com/htcfreek) for the review!
- Added support for variables in template filenames, enabling dynamic elements like date components and environment variables for enhanced customization in New+. Thanks [@cgaarden](https://github.com/cgaarden)!
- Fixed an issue where updating PowerToys on Windows 11 did not properly update context menu entries, impacting New+, PowerRename, Image Resizer, and File Locksmith.
- Updated .NET Packages from 9.0.1 to 9.0.2. Thanks [@snickler](https://github.com/snickler) for this.
- Enabled compatibility with VS17.3 and later, for C++23. Thanks [@LNKLEO](https://github.com/LNKLEO) for this.
### Color Picker
### Advanced Paste
- Replaced WPF UI with .NET WPF for the Color Picker, enhancing compatibility and improving theme support. Thanks [@mantaionut](https://github.com/mantaionut)! Thanks [@Jay-o-Way](https://github.com/Jay-o-Way) and [@niels9001](https://github.com/niels9001) for helping with the review!
- Added media transcoding support to convert different video and audio file formats, improved UI layouts, refined clipboard handling, and integrated Semantic Kernel for smarter pasting. Thanks [@snickler](https://github.com/snickler) for your help!
### Command Palette
- Introduced the Windows Command Palette ("CmdPal"), the next iteration of PowerToys Run, designed with extensibility at its core. CmdPal includes features such as searching for installed apps, shell commands, files and WinGet package installation. This module aims to provide a more powerful and flexible launcher experience. Thanks [@zadjii-msft](https://github.com/zadjii-msft), [@niels9001](https://github.com/niels9001), [@michael-hawker](https://github.com/michael-hawker), [@joadoumie](https://github.com/joadoumie), [@plante-msft](https://github.com/plante-msft), and the whole team!
### FancyZones
- Fixed accessibility by improving the text for monitors, ensuring clearer naming and help text for screen readers.
- Fixed a bug where deleting a layout resulted in incorrect data being written to the JSON file.
- Fixed a bug where layout hotkeys were displayed incorrectly, ensuring the hotkey list does not include invalid entries.
- Fixed an issue where the "None" option was missing in the editor layout.
### Image Resizer
- Fixed issues with Width and Height fields in Image Resizer's Custom preset, ensuring empty values no longer cause errors, settings save correctly, and auto-scaling behaves as expected. Thanks [@daverayment](https://github.com/daverayment)!
- Fixed accessibility by ensuring screen readers announce selected image dimensions in the combo-box for better navigation.
### Monaco Preview
- Fixed open link in default browser rather than Microsoft Edge. Thanks [@OldUser101](https://github.com/OldUser101)!
### Mouse Highlighter
- Fixed a highlight released on an Administrator window will start fading, instead of staying on the screen indefinitely until the mouse button is pressed again on an unelevated window.
- Fixed warnings in ImageResizer regarding the use of variables "shellItem" and "itemName" without being initialized.
### Mouse Without Borders
- Fixed an issue in service mode where copy-paste and drag-drop file transfers didnt work, ensuring seamless file operations.
- Enabled GPO for enable/disable for Mouse Without Borders in Service Mode. Thanks [@htcfreek](https://github.com/htcfreek) for review and comments!
- Fixed code maintainability by refactoring the oversized 'Common' class in Mouse Without Borders into smaller, focused classes for better structure and clarity. Thanks [@mikeclayton](https://github.com/mikeclayton) and thanks [@htcfreek](https://github.com/htcfreek) for review!
### PowerRename
- Supported negative value as Start value in regular expression, e.g. ${start=-1314}
- Enhanced RegEx help by adding $, ^, quantifiers, and common patterns for better usability. Thanks [@PesBandi](https://github.com/PesBandi) and thanks [@htcfreek](https://github.com/htcfreek) for review.
- Enhanced the logger to properly track the file path for easier debugging.
- Refactored the "Common" class into distinct individual classes to enhance maintainability, and updated all references and unit tests to reflect these changes. Thanks [@mikeclayton](https://github.com/mikeclayton) for this!
### New+
- Added support for variables in template filenames, including date/time components, parent folder name, and environment variables. Thanks [@cgaarden](https://github.com/cgaarden)!
### Peek
- Added the ability to delete the file currently being previewed in Peek, including navigation updates and handling for deleted items. Thanks [@daverayment](https://github.com/daverayment) and thanks [@htcfreek](https://github.com/htcfreek) for your help reviewing this!
### PowerToys Run
- Fixed crashes when loading thumbnails after the .NET 9 update by disabling CETCompat.
- Fixed PowerLauncher.exe blocking other MSI installers creating shortcuts. Thanks [@OneBlue](https://github.com/OneBlue)!
- Fixed Runs dark mode detection to work reliably, preventing issues with incorrect theme detection and ensuring a smoother user experience. Thanks [@daverayment](https://github.com/daverayment)!
- Fixed list separator handling in Calculator, allowing functions with multiple arguments to work correctly across different locales. For example pow(2;3) would be replaced with pow(2,3). Thanks [@PesBandi](https://github.com/PesBandi) and thanks [@htcfreek](https://github.com/htcfreek) for review!
- Fixed angle unit conversions in the PowerToys Run calculator, allowing quick conversions between radians, degrees, and gradians. Thanks [@OldUser101](https://github.com/OldUser101)!
### Quick Accent
- Added ǎ, ǒ and ǔ to the IPA character set. Thanks [@PesBandi](https://github.com/PesBandi)!
- Added ` (backtick) and ~ (tilde) to the VK_OEM_5 character set. Thanks [@xanatos](https://github.com/xanatos)!
- Added ς (final sigma) to the Greek character set. Thanks [@IamSmeagol](https://github.com/IamSmeagol)!
- Fixed an issue where duplicated applications were shown by ensuring the shell link helper opens .ink files non-exclusively and correctly retrieves the "FullPath". Thanks [@htcfreek](https://github.com/htcfreek) and [@davidegiacometti](https://github.com/davidegiacometti) for review!
- Fixed an issue where applying round corners on Windows 11 build 22000 caused crashes.
- Async the OnRename method to unblock the thread. Thanks [@davidegiacometti](https://github.com/davidegiacometti) for review!
- Added support for using `sq` instead of `^2` in the Unit Converter. Thanks [@PesBandi](https://github.com/PesBandi)!
### Settings
- Enabled GPO for the "run at startup" setting. Thanks [@htcfreek](https://github.com/htcfreek) for review and comments!
- Fixed accessibility issue by allowing screen readers to announce the group name for secondary links in Settings pages, instead of reading link descriptions without context.
- Fixed an issue where the Color Picker shortcut was not displaying correctly in the Dashboard.
- Disabled the spell check feature in the text boxes of plugin settings for PowerToys Run. Thanks [@htcfreek](https://github.com/htcfreek)!
- Fixed an issue where InfoBars for release notes errors were not displayed properly, and added a retry button. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
### Workspaces
- Fixed if a window was last placed on a disconnected monitor, it launches minimized and repositions within the main monitor's visible area when restored, instead of remaining off-screen and invisible.
- Fixed on ARM64 to correctly display icons for packaged apps by resolving path mismatches.
### ZoomIt
- Fixed warning C4706 and related error C2220 during build. Thanks [@xanatos](https://github.com/xanatos)!
- Fixed an issue where some minimized packaged apps (e.g., Microsoft ToDo, Settings) were not snapshotted.
### Documentation
- Fixed runner-ipc.md doc on the broken link. Thanks [@daverayment](https://github.com/daverayment)!
- Fixed the new plugin checklist by updating the target framework, removing duplicates, and improving statement organization. Thanks [@hlaueriksson](https://github.com/hlaueriksson)!
- Updated runner documentation to align with the latest code structure.
- Added the FirefoxBookmark plugin to the list of Third-Party plugins for PowerToys Run. Thanks [@8LWXpg](https://github.com/8LWXpg)!
- Added the SVGL third-party plugin to PowerToys Run, enabling users to search, browse, and copy SVG logos. Thanks [@SameerJS6](https://github.com/SameerJS6)!
- Added Monaco usage for the Registry Preview.
### Development
- Stabilized pipeline on ARM64 and forked build.
- Added fuzz testing for HostUILib, added as part of pipeline for OneFuzz.
- Fixed and improved UI-Test automation framework, and added new test cases for the FancyZones and Hosts module.
- Optimized Logger function as AOT compatible, improving performance by 18%.
- Made Common.UI and Setting.UI to be AOT compatible.
- Updated WinGet configuration file location and extension. Thanks [@mdanish-kh](https://github.com/mdanish-kh)!
- Removed the Markdown file bypass to ensure CI runs for commits that only update Markdown files.
- Fixed an issue where the default generated file path exceeded the length limit of 260 characters for EnvironmentVariablesUILib.csproj, causing build failures.
- Upgraded WindowsAppSDK to 1.6.250205002 and CsWinRT to 2.2.0. Thanks [@htcfreek](https://github.com/htcfreek) for review!
- Upgraded XamlStyler to 3.2501.8 and dotnet-consolidate to 4.2.0. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Updated .NET Packages from 9.0.2 to 9.0.3.
- Optimized the UI Test Automation Framework and added UI test cases for the Hosts File Editor module.
- Added fuzz testing for RegistryPreview.
- Added new UI tests for the FancyZones editor, including tests for creating, duplicating, editing, and deleting layouts.
- Added telemetry code to measure the module editor open time and evaluate the benefits of applying AOT.
### What is being planned for version 0.90
### What is being planned for version 0.91
For [v0.90][github-next-release-work], we'll work on the items below:
For [v0.91][github-next-release-work], we'll work on the items below:
- New module: PowerToys Run v2
- New module: File Actions Menu
- New UI Automation tests
- Working on installer upgrades
- Upgrading keyboard manager's editor UI
- Upgrading Keyboard Manager's editor UI
- Stability / bug fixes
## PowerToys Community

View File

@@ -88,4 +88,4 @@ namespace UITests_KeyboardManager
## Extra tools and information
**Accessibility Tools**:
While working on tests, you may need a tool that helps you to view the element's accessibility data, e.g. for finding the button to click. For this purpose, you could use [AccessibilityInsights](https://accessibilityinsights.io/docs/windows/overview)
While working on tests, you may need a tool that helps you to view the element's accessibility data, e.g. for finding the button to click. For this purpose, you could use [AccessibilityInsights](https://accessibilityinsights.io/docs/windows/overview).

View File

@@ -16,49 +16,70 @@ The 'Time and Date' plugin shows the date and time in different formats. For the
### Available formats
**Remarks**
- The following formats requires a prefix in the query:
- The following formats requires a prefix in the query when using them as date input:
- Unix Timestamp: `u`
- Unix Timestamp in milliseconds: `ums`
- Windows file time: `ft`
- OLE Automation date: `oa`
- Excel 1900 date value: `exc`
- Excel 1904 date value: `exf`
- On invalid number inputs we show a warning that tells the user which prefixes are allowed/required.
**List of available formats**
The following formats are currently available:
| Format | Example (Based on default settings) | As result | As input |
| Format | Example (Based on default settings) | As result | As input | Result as custom format only
|--------------|-----------|------------|------------|
| Time | 5:10 PM | x | x |
| Date | 3/5/2022 | x | x |
| Now | 3/5/2022 5:10 PM | x | x |
| Time UTC | 4:10 PM | x | x |
| Now UTC | 3/5/2022 4:10 PM | x | x |
| Unix Timestamp | 1646496622 | x | x |
| Unix Timestamp in milliseconds | 1646496622500 | x | x |
| Hour | 10 | x | |
| Minute | 30 | x | |
| Second | 45 | x | |
| Millisecond | 678 | x | |
| Day (Week day) | Saturday | x | |
| Day of the week | 6 | x | |
| Day of the month | 5 | x | |
| Day of the year | 64 | x | |
| Week of the month | 1 | x | |
| Week of the year (Calendar week, Week number) | 10 | x | |
| Month | March | x | |
| Month of the year | 3 | x | |
| Month and day | March 7 | x | x |
| Year | 2022 | x | |
| Era | AD | x | |
| Era abbreviation | A | x | |
| Month and year | March 2022 | x | x |
| Windows file time (Int64 number) | 637820976123938199 | x | x |
| Universal time format: YYYY-MM-DD hh:mm:ss| 2022-03-05 16:20:12Z | x | x |
| ISO 8601 | 2022-03-05T17:23:04 | x | x |
| ISO 8601 UTC | 2022-03-05T16:23:04 | x | x |
| ISO 8601 with time zone | 2022-03-05T17:23:04+01:00 | x | x |
| ISO 8601 UTC with time zone | 2022-03-05T16:23:04Z | x | x |
| RFC1123 | Sat, 05 Mar 2022 16:23:04 GMT | x | x |
| Time | 5:10 PM | x | x | |
| Date | 3/5/2022 | x | x | |
| Now | 3/5/2022 5:10 PM | x | x | |
| Time UTC | 4:10 PM | x | x | |
| Now UTC | 3/5/2022 4:10 PM | x | x | |
| Unix Timestamp | 1646496622 | x | x | |
| Unix Timestamp in milliseconds | 1646496622500 | x | x | |
| Hour | 10 | x | | |
| Minute | 30 | x | | |
| Second | 45 | x | | |
| Millisecond | 678 | x | | |
| Day (Week day) | Saturday | x | | |
| Day of the week | 6 | x | | |
| Day of the month | 5 | x | | |
| Day of the year | 64 | x | | |
| Week of the month | 1 | x | | |
| Week of the year (Calendar week, Week number) | 10 | x | | |
| Month | March | x | | |
| Month of the year | 3 | x | | |
| Month and day | March 7 | x | x | |
| Year | 2022 | x | | |
| Era | AD | x | | |
| Era abbreviation | A | x | | |
| Month and year | March 2022 | x | x | |
| Windows file time (Int64 number) | 637820976123938199 | x | x | |
| Universal time format: YYYY-MM-DD hh:mm:ss| 2022-03-05 16:20:12Z | x | x | |
| ISO 8601 | 2022-03-05T17:23:04 | x | x | |
| ISO 8601 UTC | 2022-03-05T16:23:04 | x | x | |
| ISO 8601 with time zone | 2022-03-05T17:23:04+01:00 | x | x | |
| ISO 8601 UTC with time zone | 2022-03-05T16:23:04Z | x | x | |
| RFC1123 | Sat, 05 Mar 2022 16:23:04 GMT | x | x | |
| OLE Automation date | 45723.44143763889 | | x | x |
| Excel's 1900 date value | 45723.44143763889 | | x | x |
| Excel's 1904 date value | 44261.44143763889 | | x | x |
**Custom format definition**
The user can create its own formats. One per line in the settings text box. The format of each line is `<name>=<syntax pattern>`.
If the syntax pattern starting with `UTC:` then we use the UTC time instead of the local time.
As syntax pattern the pattern from `DateTime.ToString()` and the following custom pattern are available:
- DOW: Number of the day in the week.
- WOM: Number of week in the month.
- WOY: Number of the week in the year.
- EAB: Era abbreviation.
- WFT: Windows file time.
- UXT: Unix time stamp.
- UMS: Unix time stamp in milliseconds.
- OAD: OLE Automation date.
- EXC: Excel's 1900 based date value.
- EXF: Excel's 1904 based date value.
### Add new formats
- To add a new formats you have to add them to the method `GetList()` of the [`AvailableResultsList`](/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Components/AvailableResultsList.cs) class.
@@ -73,13 +94,13 @@ The following formats are currently available:
| Key | Type | Default value | Name | Description |
|--------------|--------------|-----------|------------|------------|
| `CalendarFirstWeekRule` | Combo box | `-1` (Use system settings) | First week of the year | Configure the calendar rule for the first week of the year. |
| `FirstDayOfWeek` | Combo box | `-1` (Use system settings) | First day of the week | |
| `OnlyDateTimeNowGlobal` | Checkbox | `true` | Show only 'Time', 'Date', and 'Now' result for system time on global queries | Regardless of this setting, for global queries the first word of the query has to be a complete match. |
| `TimeWithSeconds` | Checkbox | `false` | Show time with seconds | This setting applies to the 'Time' and 'Now' result. |
| `DateWithWeekday` | Checkbox | `false` | Show date with weekday and name of month | This setting applies to the 'Date' and 'Now' result. |
| `HideNumberMessageOnGlobalQuery` | Checkbox | `false` | Hide 'Invalid number input' error message on global queries | |
| `CalendarFirstWeekRule` | Combo box | `-1` (Use system settings) | First week of the year | Configure the calendar rule for the first week of the year. |
| `FirstDayOfWeek` | Combo box | `-1` (Use system settings) | First day of the week | |
| `CustomFormats` | Multiline text box | `string.Empty` | Custom formats | Use date and time string format syntax and DOW (Day of Week), WOM (Week of Month), WOY (Week of the year), EAB (Era abbreviation), WFT (Windows File Time), UXT (Unix Time), UMS (Unix Time in milliseconds), OAD (OLE Automation date), EXC (Excel's 1900 based date value), EXF (Excel's 1904 based date value). If the format starts with UTC:, then Universal Time (UTC) is used. (Use a backslash to escape format sequences and the backslash character as text.) |
## Classes

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

View File

@@ -40,7 +40,6 @@
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes"/>
</RegistryKey>
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx" />
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\x64\Microsoft.WindowsAppRuntime.1.6.msix" />
</Component>
</DirectoryRef>
<?else ?>
@@ -50,7 +49,6 @@
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes"/>
</RegistryKey>
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\arm64\Microsoft.VCLibs.ARM64.14.00.Desktop.appx" />
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion).0_Test\Dependencies\arm64\Microsoft.WindowsAppRuntime.1.6.msix" />
</Component>
</DirectoryRef>
<?endif ?>

View File

@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Some items may be set in Directory.Build.props in root -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Since WinAppSDK already depends on .NET, each .csproj shouldn't separately include an additional .NET self-contained props file. Instead, we centralize the inclusion here. -->
<Import Project=".\Common.SelfContained.props" />
<PropertyGroup>
<WindowsSdkPackageVersion>10.0.22621.57</WindowsSdkPackageVersion>
<TargetFramework>net9.0-windows10.0.22621.0</TargetFramework>

View File

@@ -2,11 +2,14 @@
#include <Windows.h>
#include <appxpackaging.h>
#include <exception>
#include <filesystem>
#include <regex>
#include <string>
#include <optional>
#include <Shlwapi.h>
#include <wrl/client.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Foundation.h>
@@ -15,11 +18,12 @@
#include "../logger/logger.h"
#include "../version/version.h"
namespace package {
namespace package
{
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::ApplicationModel;
using namespace winrt::Windows::Management::Deployment;
using Microsoft::WRL::ComPtr;
inline BOOL IsWin11OrGreater()
{
@@ -46,6 +50,118 @@ namespace package {
dwlConditionMask);
}
struct PACKAGE_VERSION
{
UINT16 Major;
UINT16 Minor;
UINT16 Build;
UINT16 Revision;
};
class ComInitializer
{
public:
explicit ComInitializer(DWORD coInitFlags = COINIT_MULTITHREADED) :
_initialized(false)
{
const HRESULT hr = CoInitializeEx(nullptr, coInitFlags);
_initialized = SUCCEEDED(hr);
}
~ComInitializer()
{
if (_initialized)
{
CoUninitialize();
}
}
bool Succeeded() const { return _initialized; }
private:
bool _initialized;
};
inline bool GetPackageNameAndVersionFromAppx(
const std::wstring& appxPath,
std::wstring& outName,
PACKAGE_VERSION& outVersion)
{
try
{
ComInitializer comInit;
if (!comInit.Succeeded())
{
Logger::error(L"COM initialization failed.");
return false;
}
ComPtr<IAppxFactory> factory;
ComPtr<IStream> stream;
ComPtr<IAppxPackageReader> reader;
ComPtr<IAppxManifestReader> manifest;
ComPtr<IAppxManifestPackageId> packageId;
HRESULT hr = CoCreateInstance(__uuidof(AppxFactory), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory));
if (FAILED(hr))
return false;
hr = SHCreateStreamOnFileEx(appxPath.c_str(), STGM_READ | STGM_SHARE_DENY_WRITE, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &stream);
if (FAILED(hr))
return false;
hr = factory->CreatePackageReader(stream.Get(), &reader);
if (FAILED(hr))
return false;
hr = reader->GetManifest(&manifest);
if (FAILED(hr))
return false;
hr = manifest->GetPackageId(&packageId);
if (FAILED(hr))
return false;
LPWSTR name = nullptr;
hr = packageId->GetName(&name);
if (FAILED(hr))
return false;
UINT64 version = 0;
hr = packageId->GetVersion(&version);
if (FAILED(hr))
return false;
outName = std::wstring(name);
CoTaskMemFree(name);
outVersion.Major = static_cast<UINT16>((version >> 48) & 0xFFFF);
outVersion.Minor = static_cast<UINT16>((version >> 32) & 0xFFFF);
outVersion.Build = static_cast<UINT16>((version >> 16) & 0xFFFF);
outVersion.Revision = static_cast<UINT16>(version & 0xFFFF);
Logger::info(L"Package name: {}, version: {}.{}.{}.{}, appxPath: {}",
outName,
outVersion.Major,
outVersion.Minor,
outVersion.Build,
outVersion.Revision,
appxPath);
return true;
}
catch (const std::exception& ex)
{
Logger::error(L"Standard exception: {}", winrt::to_hstring(ex.what()));
return false;
}
catch (...)
{
Logger::error(L"Unknown or non-standard exception occurred.");
return false;
}
}
inline std::optional<Package> GetRegisteredPackage(std::wstring packageDisplayName, bool checkVersion)
{
PackageManager packageManager;
@@ -229,6 +345,59 @@ namespace package {
return matchedFiles;
}
inline bool IsPackageSatisfied(const std::wstring& appxPath)
{
std::wstring targetName;
PACKAGE_VERSION targetVersion{};
if (!GetPackageNameAndVersionFromAppx(appxPath, targetName, targetVersion))
{
Logger::error(L"Failed to get package name and version from appx: " + appxPath);
return false;
}
PackageManager pm;
for (const auto& package : pm.FindPackagesForUser({}))
{
const auto& id = package.Id();
if (std::wstring(id.Name()) == targetName)
{
const auto& version = id.Version();
if (version.Major > targetVersion.Major ||
(version.Major == targetVersion.Major && version.Minor > targetVersion.Minor) ||
(version.Major == targetVersion.Major && version.Minor == targetVersion.Minor && version.Build > targetVersion.Build) ||
(version.Major == targetVersion.Major && version.Minor == targetVersion.Minor && version.Build == targetVersion.Build && version.Revision >= targetVersion.Revision))
{
Logger::info(
L"Package {} is already satisfied with version {}.{}.{}.{}; target version {}.{}.{}.{}; appxPath: {}",
id.Name(),
version.Major,
version.Minor,
version.Build,
version.Revision,
targetVersion.Major,
targetVersion.Minor,
targetVersion.Build,
targetVersion.Revision,
appxPath);
return true;
}
}
}
Logger::info(
L"Package {} is not satisfied. Target version: {}.{}.{}.{}; appxPath: {}",
targetName,
targetVersion.Major,
targetVersion.Minor,
targetVersion.Build,
targetVersion.Revision,
appxPath);
return false;
}
inline bool RegisterPackage(std::wstring pkgPath, std::vector<std::wstring> dependencies)
{
try
@@ -238,7 +407,7 @@ namespace package {
PackageManager packageManager;
// Declare use of an external location
DeploymentOptions options = DeploymentOptions::ForceApplicationShutdown;
DeploymentOptions options = DeploymentOptions::ForceTargetApplicationShutdown;
Collections::IVector<Uri> uris = winrt::single_threaded_vector<Uri>();
if (!dependencies.empty())
@@ -247,7 +416,14 @@ namespace package {
{
try
{
uris.Append(Uri(dependency));
if (IsPackageSatisfied(dependency))
{
Logger::info(L"Dependency already satisfied: {}", dependency);
}
else
{
uris.Append(Uri(dependency));
}
}
catch (const winrt::hresult_error& ex)
{
@@ -282,7 +458,6 @@ namespace package {
{
Logger::debug(L"Register {} package started.", pkgPath);
}
}
catch (std::exception& e)
{
@@ -293,4 +468,4 @@ namespace package {
return true;
}
}
}

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.FileLocksmith</AssemblyTitle>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.MeasureTool</AssemblyTitle>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
@@ -37,4 +36,4 @@
<ProjectReference Include="..\MouseJump.Common\MouseJump.Common.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
@@ -72,4 +71,4 @@
<PropertyGroup>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
@@ -248,4 +247,4 @@
<PropertyGroup>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>true</ImplicitUsings>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.PowerOCR</AssemblyTitle>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.WorkspacesEditor</AssemblyTitle>
@@ -96,4 +95,4 @@
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.WorkspacesLauncherUI</AssemblyTitle>
@@ -99,4 +98,4 @@
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>

View File

@@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.CmdPal.Ext.TimeDate.Helpers;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
@@ -12,6 +14,12 @@ namespace Microsoft.CmdPal.Ext.TimeDate.Pages;
internal sealed partial class TimeDateExtensionPage : DynamicListPage
{
private readonly Lock _resultsLock = new();
private IList<ListItem> _results = new List<ListItem>();
private bool initialized;
private SettingsManager _settingsManager;
public TimeDateExtensionPage(SettingsManager settingsManager)
@@ -24,20 +32,36 @@ internal sealed partial class TimeDateExtensionPage : DynamicListPage
_settingsManager = settingsManager;
}
public override IListItem[] GetItems() => DoExecuteSearch(SearchText).ToArray();
public override IListItem[] GetItems()
{
if (!initialized)
{
DoExecuteSearch(string.Empty);
}
lock (_resultsLock)
{
ListItem[] results = _results.ToArray();
return results;
}
}
public override void UpdateSearchText(string oldSearch, string newSearch)
{
if (newSearch == oldSearch)
{
return;
}
DoExecuteSearch(newSearch);
RaiseItemsChanged(0);
}
private List<ListItem> DoExecuteSearch(string query)
private void DoExecuteSearch(string query)
{
try
{
var result = TimeDateCalculator.ExecuteSearch(_settingsManager, query);
return result;
UpdateResult(result);
}
catch (Exception)
{
@@ -51,7 +75,18 @@ internal sealed partial class TimeDateExtensionPage : DynamicListPage
ResultHelper.CreateInvalidInputErrorResult(),
};
return items;
UpdateResult(items);
}
}
private void UpdateResult(IList<ListItem> result)
{
lock (_resultsLock)
{
initialized = true;
this._results = result;
}
RaiseItemsChanged(this._results.Count);
}
}

View File

@@ -295,7 +295,7 @@
"Areas": [ "AreaEaseOfAccess" ],
"Type": "AppSettingsApp",
"AltNames": [ "TouchFeedback" ],
"Command": "ms-settings:easeofaccess-MousePointer"
"Command": "ms-settings:easeofaccess-mousepointer"
},
{
"Name": "Display",

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using ManagedCommon;
using Microsoft.CmdPal.Common.Helpers;
using Microsoft.CmdPal.Common.Services;
using Microsoft.CmdPal.Ext.Apps;
@@ -78,7 +79,7 @@ public partial class App : Application
var cmdArgs = Environment.GetCommandLineArgs();
bool runFromPT = false;
var runFromPT = false;
foreach (var arg in cmdArgs)
{
if (arg == "RunFromPT")
@@ -107,9 +108,6 @@ public partial class App : Application
// Built-in Commands. Order matters - this is the order they'll be presented by default.
var allApps = new AllAppsCommandProvider();
var winget = new WinGetExtensionCommandsProvider();
var callback = allApps.LookupApp;
winget.SetAllLookup(callback);
services.AddSingleton<ICommandProvider>(allApps);
services.AddSingleton<ICommandProvider, ShellCommandsProvider>();
services.AddSingleton<ICommandProvider, CalculatorCommandProvider>();
@@ -120,7 +118,25 @@ public partial class App : Application
// services.AddSingleton<ICommandProvider, ClipboardHistoryCommandsProvider>();
services.AddSingleton<ICommandProvider, WindowWalkerCommandsProvider>();
services.AddSingleton<ICommandProvider, WebSearchCommandsProvider>();
services.AddSingleton<ICommandProvider>(winget);
// GH #38440: Users might not have WinGet installed! Or they might have
// a ridiculously old version. Or might be running as admin.
// We shouldn't explode in the App ctor if we fail to instantiate an
// instance of PackageManager, which will happen in the static ctor
// for WinGetStatics
try
{
var winget = new WinGetExtensionCommandsProvider();
var callback = allApps.LookupApp;
winget.SetAllLookup(callback);
services.AddSingleton<ICommandProvider>(winget);
}
catch (Exception ex)
{
Logger.LogError("Couldn't load winget");
Logger.LogError(ex.ToString());
}
services.AddSingleton<ICommandProvider, WindowsTerminalCommandsProvider>();
services.AddSingleton<ICommandProvider, WindowsSettingsCommandsProvider>();
services.AddSingleton<ICommandProvider, RegistryCommandsProvider>();

View File

@@ -105,19 +105,8 @@ public sealed partial class SearchBar : UserControl,
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
var altPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down);
if (e.Key == VirtualKey.Down)
{
WeakReferenceMessenger.Default.Send<NavigateNextCommand>();
e.Handled = true;
}
else if (e.Key == VirtualKey.Up)
{
WeakReferenceMessenger.Default.Send<NavigatePreviousCommand>();
e.Handled = true;
}
else if (ctrlPressed && e.Key == VirtualKey.Enter)
if (ctrlPressed && e.Key == VirtualKey.Enter)
{
// ctrl+enter
WeakReferenceMessenger.Default.Send<ActivateSecondaryCommandMessage>();
@@ -197,6 +186,18 @@ public sealed partial class SearchBar : UserControl,
_isBackspaceHeld = true;
}
}
else if (e.Key == VirtualKey.Up)
{
WeakReferenceMessenger.Default.Send<NavigatePreviousCommand>();
e.Handled = true;
}
else if (e.Key == VirtualKey.Down)
{
WeakReferenceMessenger.Default.Send<NavigateNextCommand>();
e.Handled = true;
}
}
private void FilterBox_PreviewKeyUp(object sender, KeyRoutedEventArgs e)

View File

@@ -187,6 +187,10 @@ public sealed partial class ListPage : Page,
{
ItemsList.SelectedIndex++;
}
else
{
ItemsList.SelectedIndex = 0;
}
}
public void Receive(NavigatePreviousCommand message)
@@ -195,6 +199,10 @@ public sealed partial class ListPage : Page,
{
ItemsList.SelectedIndex--;
}
else
{
ItemsList.SelectedIndex = ItemsList.Items.Count - 1;
}
}
public void Receive(ActivateSelectedListItemMessage message)

View File

@@ -13,6 +13,7 @@
<EnableMsixTooling>true</EnableMsixTooling>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<Version>$(CmdPalVersion)</Version>

View File

@@ -19,6 +19,7 @@ SetFocus
SetActiveWindow
MonitorFromWindow
GetMonitorInfo
GetDpiForMonitor
SHCreateStreamOnFileEx
CoAllowSetForegroundWindow
SHCreateStreamOnFileEx

View File

@@ -4,6 +4,7 @@
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.WinUI;
using ManagedCommon;
using Microsoft.CmdPal.UI.Helpers;
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.Messages;
@@ -13,6 +14,8 @@ using Microsoft.UI.Xaml;
using Windows.Graphics;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Gdi;
using Windows.Win32.UI.HiDpi;
using Windows.Win32.UI.WindowsAndMessaging;
using RS_ = Microsoft.CmdPal.UI.Helpers.ResourceLoaderInstance;
@@ -44,6 +47,21 @@ public sealed partial class ToastWindow : Window,
WeakReferenceMessenger.Default.Register<QuitMessage>(this);
}
private static double GetScaleFactor(HWND hwnd)
{
try
{
var monitor = PInvoke.MonitorFromWindow(hwnd, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
_ = PInvoke.GetDpiForMonitor(monitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var dpiX, out _);
return dpiX / 96.0;
}
catch (Exception ex)
{
Logger.LogError($"Failed to get scale factor, error: {ex.Message}");
return 1.0;
}
}
private void PositionCentered()
{
var intSize = new SizeInt32
@@ -51,7 +69,14 @@ public sealed partial class ToastWindow : Window,
Width = Convert.ToInt32(ToastText.ActualWidth),
Height = Convert.ToInt32(ToastText.ActualHeight),
};
AppWindow.Resize(intSize);
var scaleAdjustment = GetScaleFactor(_hwnd);
var scaled = new SizeInt32
{
Width = (int)Math.Round(intSize.Width * scaleAdjustment),
Height = (int)Math.Round(intSize.Height * scaleAdjustment),
};
AppWindow.Resize(scaled);
var displayArea = DisplayArea.GetFromWindowId(AppWindow.Id, DisplayAreaFallback.Nearest);
if (displayArea is not null)

View File

@@ -189,7 +189,7 @@ public partial class InstallPackageListItem : ListItem
private void InstallStateChangedHandler(object? sender, InstallPackageCommand e)
{
if (!ApiInformation.IsApiContractPresent("Microsoft.Management.Deployment", 12))
if (!ApiInformation.IsApiContractPresent("Microsoft.Management.Deployment.WindowsPackageManagerContract", 12))
{
Logger.LogError($"RefreshPackageCatalogAsync isn't available");
e.FakeChangeStatus();

View File

@@ -12,6 +12,7 @@ using System.Threading.Tasks;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Management.Deployment;
using Windows.Foundation.Metadata;
using WindowsPackageManager.Interop;
namespace Microsoft.CmdPal.Ext.WinGet;
@@ -51,9 +52,12 @@ internal static class WinGetStatics
_storeCatalog,
];
foreach (var catalogReference in AvailableCatalogs)
if (ApiInformation.IsApiContractPresent("Microsoft.Management.Deployment.WindowsPackageManagerContract", 8))
{
catalogReference.PackageCatalogBackgroundUpdateInterval = new(0);
foreach (var catalogReference in AvailableCatalogs)
{
catalogReference.PackageCatalogBackgroundUpdateInterval = new(0);
}
}
// Immediately start the lazy-init of the all packages catalog, but

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.ColorPickerUI</AssemblyTitle>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.FancyZonesEditor</AssemblyTitle>
@@ -63,4 +62,4 @@
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.ImageResizer</AssemblyTitle>
@@ -55,4 +54,4 @@
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.PowerToys.Run.Plugin.TimeDate.Components;
@@ -23,7 +24,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
var result = settings?.Length;
// Assert
Assert.AreEqual(6, result);
Assert.AreEqual(7, result);
}
[DataTestMethod]
@@ -33,6 +34,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
[DataRow("TimeWithSeconds")]
[DataRow("DateWithWeekday")]
[DataRow("HideNumberMessageOnGlobalQuery")]
[DataRow("CustomFormats")]
public void DoesSettingExist(string name)
{
// Setup
@@ -78,5 +80,20 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
// Assert
Assert.AreEqual(valueExpected, result);
}
[DataTestMethod]
[DataRow("CustomFormats")]
public void DefaultEmptyMultilineTextValues(string name)
{
// Setup
TimeDateSettings setting = TimeDateSettings.Instance;
// Act
PropertyInfo propertyInfo = setting?.GetType()?.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Instance);
List<string> result = (List<string>)propertyInfo?.GetValue(setting);
// Assert
Assert.AreEqual(0, result.Count);
}
}
}

View File

@@ -54,11 +54,11 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
[DataTestMethod]
[DataRow("(time", 18)]
[DataRow("(date", 26)]
[DataRow("(year", 7)]
[DataRow("(now", 32)]
[DataRow("(current", 32)]
[DataRow("(", 32)]
[DataRow("(date", 28)]
[DataRow("(year", 8)]
[DataRow("(now", 34)]
[DataRow("(current", 34)]
[DataRow("(", 34)]
[DataRow("(now::10:10:10", 1)] // Windows file time
[DataRow("(current::10:10:10", 0)]
public void CountWithPluginKeyword(string typedString, int expectedResultCount)
@@ -140,6 +140,8 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
[DataRow("(week day", "Day of the week (Week day) -")]
[DataRow("(cal week", "Week of the year (Calendar week, Week number) -")]
[DataRow("(week num", "Week of the year (Calendar week, Week number) -")]
[DataRow("(days in mo", "Days in month -")]
[DataRow("(Leap y", "Leap year -")]
public void CanFindFormatResult(string typedString, string expectedResult)
{
// Setup

View File

@@ -41,10 +41,29 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
[DataRow("ums-10456", true, "", "")] // Value is UTC and can be different based on system
[DataRow("ums+10456", true, "", "")] // Value is UTC and can be different based on system
[DataRow("ft10456", true, "", "")] // Value is UTC and can be different based on system
[DataRow("oa-657434.99999999", true, "G", "1/1/0100 11:59:59 PM")]
[DataRow("oa2958465.99999999", true, "G", "12/31/9999 11:59:59 PM")]
[DataRow("oa-657435", false, "", "")] // Value to low
[DataRow("oa2958466", false, "", "")] // Value to large
[DataRow("exc1.99998843", true, "G", "1/1/1900 11:59:59 PM")]
[DataRow("exc59.99998843", true, "G", "2/28/1900 11:59:59 PM")]
[DataRow("exc61", true, "G", "3/1/1900 12:00:00 AM")]
[DataRow("exc62.99998843", true, "G", "3/2/1900 11:59:59 PM")]
[DataRow("exc2958465.99998843", true, "G", "12/31/9999 11:59:59 PM")]
[DataRow("exc0", false, "", "")] // Day 0 means in Excel 0/1/1900 and this is a fake date.
[DataRow("exc0.99998843", false, "", "")] // Day 0 means in Excel 0/1/1900 and this is a fake date.
[DataRow("exc60.99998843", false, "", "")] // Day 60 means in Excel 2/29/1900 and this is a fake date in Excel which we cannot support.
[DataRow("exc60", false, "", "")] // Day 60 means in Excel 2/29/1900 and this is a fake date in Excel which we cannot support.
[DataRow("exc-1", false, "", "")] // Value to low
[DataRow("exc2958466", false, "", "")] // Value to large
[DataRow("exf0.99998843", true, "G", "1/1/1904 11:59:59 PM")]
[DataRow("exf2957003.99998843", true, "G", "12/31/9999 11:59:59 PM")]
[DataRow("exf-0.5", false, "", "")] // Value to low
[DataRow("exf2957004", false, "", "")] // Value to large
public void ConvertStringToDateTime(string typedString, bool expectedBool, string stringType, string expectedString)
{
// Act
bool boolResult = TimeAndDateHelper.ParseStringAsDateTime(in typedString, out DateTime result);
bool boolResult = TimeAndDateHelper.ParseStringAsDateTime(in typedString, out DateTime result, out string _);
// Assert
Assert.AreEqual(expectedBool, boolResult);

View File

@@ -13,6 +13,19 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
[TestClass]
public class TimeAndDateHelperTests
{
private CultureInfo originalCulture;
private CultureInfo originalUiCulture;
[TestInitialize]
public void Setup()
{
// Set culture to 'en-us'
originalCulture = CultureInfo.CurrentCulture;
CultureInfo.CurrentCulture = new CultureInfo("en-us", false);
originalUiCulture = CultureInfo.CurrentUICulture;
CultureInfo.CurrentUICulture = new CultureInfo("en-us", false);
}
[DataTestMethod]
[DataRow(-1, null)] // default setting
[DataRow(0, CalendarWeekRule.FirstDay)]
@@ -62,5 +75,103 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
Assert.AreEqual(valueExpected, result);
}
}
[DataTestMethod]
[DataRow(0, "12/30/1899 12:00 PM", 0.5)] // OLE Automation date
[DataRow(1, "12/31/1898 12:00 PM", null)] // Excel based 1900: Date to low
[DataRow(1, "1/1/1900, 00:00 AM", 1.0)] // Excel based 1900
[DataRow(2, "12/31/1898 12:00 PM", null)] // Excel based 1904: Date to low
[DataRow(2, "1/1/1904, 00:00 AM", 0.0)] // Excel based 1904
public void ConvertToOADateFormat(int type, string date, double? valueExpected)
{
// Act
DateTime dt = DateTime.Parse(date, DateTimeFormatInfo.CurrentInfo);
// Assert
if (valueExpected == null)
{
Assert.ThrowsException<ArgumentOutOfRangeException>(() => TimeAndDateHelper.ConvertToOleAutomationFormat(dt, (OADateFormats)type));
}
else
{
var result = TimeAndDateHelper.ConvertToOleAutomationFormat(dt, (OADateFormats)type);
Assert.AreEqual(valueExpected, result);
}
}
[DataTestMethod]
[DataRow("dow")]
[DataRow("\\DOW")]
[DataRow("wom")]
[DataRow("\\WOM")]
[DataRow("woy")]
[DataRow("\\WOY")]
[DataRow("eab")]
[DataRow("\\EAB")]
[DataRow("wft")]
[DataRow("\\WFT")]
[DataRow("uxt")]
[DataRow("\\UXT")]
[DataRow("ums")]
[DataRow("\\UMS")]
[DataRow("oad")]
[DataRow("\\OAD")]
[DataRow("exc")]
[DataRow("\\EXC")]
[DataRow("exf")]
[DataRow("\\EXF")]
[DataRow("My super Test String with \\EXC pattern.")]
public void CustomFormatIgnoreInvalidPattern(string format)
{
// Act
string result = TimeAndDateHelper.ConvertToCustomFormat(DateTime.Now, 0, 0, 1, "AD", format, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
// Assert
Assert.AreEqual(format, result);
}
[DataTestMethod]
[DataRow("DOW")]
[DataRow("DIM")]
[DataRow("WOM")]
[DataRow("WOY")]
[DataRow("EAB")]
[DataRow("WFT")]
[DataRow("UXT")]
[DataRow("UMS")]
[DataRow("OAD")]
[DataRow("EXC")]
[DataRow("EXF")]
public void CustomFormatReplacesValidPattern(string format)
{
// Act
string result = TimeAndDateHelper.ConvertToCustomFormat(DateTime.Now, 0, 0, 1, "AD", format, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
// Assert
Assert.IsFalse(result.Contains(format, StringComparison.CurrentCulture));
}
[DataTestMethod]
[DataRow("01/01/0001", 1)] // First possible date
[DataRow("12/31/9999", 5)] // Last possible date
[DataRow("03/20/2025", 4)]
[DataRow("09/01/2025", 1)] // First day in month is first day of week
[DataRow("03/03/2025", 2)] // First monday is in second week
public void GetWeekOfMonth(string date, int week)
{
// Act
int result = TimeAndDateHelper.GetWeekOfMonth(DateTime.Parse(date, CultureInfo.GetCultureInfo("en-us")), DayOfWeek.Monday);
// Assert
Assert.AreEqual(result, week);
}
[TestCleanup]
public void CleanUp()
{
// Set culture to original value
CultureInfo.CurrentCulture = originalCulture;
CultureInfo.CurrentUICulture = originalUiCulture;
}
}
}

View File

@@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
{
internal class AvailableResult
internal sealed class AvailableResult
{
/// <summary>
/// Gets or sets the time/date value
@@ -41,6 +41,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
ResultIconType.Time => $"Images\\time.{theme}.png",
ResultIconType.Date => $"Images\\calendar.{theme}.png",
ResultIconType.DateTime => $"Images\\timeDate.{theme}.png",
ResultIconType.Error => $"Images\\Warning.{theme}.png",
_ => string.Empty,
};
}
@@ -51,5 +52,6 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
Time,
Date,
DateTime,
Error,
}
}

View File

@@ -6,7 +6,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.PowerToys.Run.Plugin.TimeDate.Properties;
namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
@@ -72,6 +72,86 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
string era = DateTimeFormatInfo.CurrentInfo.GetEraName(calendar.GetEra(dateTimeNow));
string eraShort = DateTimeFormatInfo.CurrentInfo.GetAbbreviatedEraName(calendar.GetEra(dateTimeNow));
// Custom formats
foreach (string f in TimeDateSettings.Instance.CustomFormats)
{
string[] formatParts = f.Split("=", 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
string formatSyntax = formatParts.Length == 2 ? formatParts[1] : string.Empty;
string searchTags = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagCustom");
DateTime dtObject = dateTimeNow;
// If Length = 0 then empty string.
if (formatParts.Length >= 1)
{
try
{
// Verify and check input and update search tags
if (formatParts.Length == 1)
{
throw new FormatException("Format syntax part after equal sign is missing.");
}
bool containsCustomSyntax = TimeAndDateHelper.StringContainsCustomFormatSyntax(formatSyntax);
if (formatSyntax.StartsWith("UTC:", StringComparison.InvariantCulture))
{
searchTags = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagCustomUtc");
dtObject = dateTimeNowUtc;
}
// Get formated date
var value = TimeAndDateHelper.ConvertToCustomFormat(dtObject, unixTimestamp, unixTimestampMilliseconds, weekOfYear, eraShort, Regex.Replace(formatSyntax, "^UTC:", string.Empty), firstWeekRule, firstDayOfTheWeek);
try
{
value = dtObject.ToString(value, CultureInfo.CurrentCulture);
}
catch
{
if (!containsCustomSyntax)
{
throw;
}
else
{
// Do not fail as we have custom format syntax. Instead fix backslashes.
value = Regex.Replace(value, @"(?<!\\)\\", string.Empty).Replace("\\\\", "\\");
}
}
// Add result
results.Add(new AvailableResult()
{
Value = value,
Label = formatParts[0],
AlternativeSearchTag = searchTags,
IconType = ResultIconType.DateTime,
});
}
catch (ArgumentOutOfRangeException e)
{
Wox.Plugin.Logger.Log.Exception($"Failed to convert into custom format {formatParts[0]}: {formatSyntax}", e, typeof(AvailableResultsList));
results.Add(new AvailableResult()
{
Value = Resources.Microsoft_plugin_timedate_ErrorConvertCustomFormat + " " + e.Message,
Label = formatParts[0],
AlternativeSearchTag = searchTags,
IconType = ResultIconType.Error,
});
}
catch (Exception e)
{
Wox.Plugin.Logger.Log.Exception($"Failed to convert into custom format {formatParts[0]}: {formatSyntax}", e, typeof(AvailableResultsList));
results.Add(new AvailableResult()
{
Value = Resources.Microsoft_plugin_timedate_InvalidCustomFormat + " " + formatSyntax,
Label = formatParts[0],
AlternativeSearchTag = searchTags,
IconType = ResultIconType.Error,
});
}
}
}
// Predefined formats
results.AddRange(new[]
{
new AvailableResult()
@@ -152,6 +232,13 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = DateTime.DaysInMonth(dateTimeNow.Year, dateTimeNow.Month).ToString(CultureInfo.CurrentCulture),
Label = Resources.Microsoft_plugin_timedate_DaysInMonth,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"),
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = dateTimeNow.DayOfYear.ToString(CultureInfo.CurrentCulture),
Label = Resources.Microsoft_plugin_timedate_DayOfYear,
@@ -201,6 +288,13 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = DateTime.IsLeapYear(dateTimeNow.Year) ? Resources.Microsoft_plugin_timedate_LeapYear : Resources.Microsoft_plugin_timedate_NoLeapYear,
Label = Resources.Microsoft_plugin_timedate_LeapYear,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"),
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = era,
Label = Resources.Microsoft_plugin_timedate_Era,
@@ -221,13 +315,31 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"),
IconType = ResultIconType.Date,
},
new AvailableResult()
});
try
{
results.Add(new AvailableResult()
{
Value = dateTimeNow.ToFileTime().ToString(CultureInfo.CurrentCulture),
Label = Resources.Microsoft_plugin_timedate_WindowsFileTime,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"),
IconType = ResultIconType.DateTime,
},
});
}
catch
{
results.Add(new AvailableResult()
{
Value = Resources.Microsoft_plugin_timedate_ErrorConvertWft,
Label = Resources.Microsoft_plugin_timedate_WindowsFileTime,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"),
IconType = ResultIconType.Error,
});
}
results.AddRange(new[]
{
new AvailableResult()
{
Value = dateTimeNowUtc.ToString("u"),

View File

@@ -83,10 +83,10 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
/// Gets a result with an error message that only numbers can't be parsed
/// </summary>
/// <returns>Element of type <see cref="Result"/>.</returns>
internal static Result CreateNumberErrorResult(string theme) => new Result()
internal static Result CreateNumberErrorResult(string theme, string title, string subtitle) => new Result()
{
Title = Resources.Microsoft_plugin_timedate_ErrorResultTitle,
SubTitle = Resources.Microsoft_plugin_timedate_ErrorResultSubTitle,
Title = title,
SubTitle = subtitle,
ToolTipData = new ToolTipData(Resources.Microsoft_plugin_timedate_ErrorResultTitle, Resources.Microsoft_plugin_timedate_ErrorResultSubTitle),
IcoPath = $"Images\\Warning.{theme}.png",
};

View File

@@ -40,9 +40,12 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
List<AvailableResult> availableFormats = new List<AvailableResult>();
List<Result> results = new List<Result>();
bool isKeywordSearch = !string.IsNullOrEmpty(query.ActionKeyword);
bool isEmptySearchInput = string.IsNullOrEmpty(query.Search);
bool isEmptySearchInput = string.IsNullOrWhiteSpace(query.Search);
string searchTerm = query.Search;
// Last input parsing error
string lastInputParsingErrorReason = string.Empty;
// Conjunction search without keyword => return no results
// (This improves the results on global queries.)
if (!isKeywordSearch && _conjunctionList.Any(x => x.Equals(searchTerm, StringComparison.CurrentCultureIgnoreCase)))
@@ -61,13 +64,13 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
{
// Search for specified format with specified time/date value
var userInput = searchTerm.Split(InputDelimiter);
if (TimeAndDateHelper.ParseStringAsDateTime(userInput[1], out DateTime timestamp))
if (TimeAndDateHelper.ParseStringAsDateTime(userInput[1], out DateTime timestamp, out lastInputParsingErrorReason))
{
availableFormats.AddRange(AvailableResultsList.GetList(isKeywordSearch, null, null, timestamp));
searchTerm = userInput[0];
}
}
else if (TimeAndDateHelper.ParseStringAsDateTime(searchTerm, out DateTime timestamp))
else if (TimeAndDateHelper.ParseStringAsDateTime(searchTerm, out DateTime timestamp, out lastInputParsingErrorReason))
{
// Return all formats for specified time/date value
availableFormats.AddRange(AvailableResultsList.GetList(isKeywordSearch, null, null, timestamp));
@@ -122,12 +125,15 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
}
// If search term is only a number that can't be parsed return an error message
if (!isEmptySearchInput && results.Count == 0 && Regex.IsMatch(searchTerm, @"\w+\d+.*$") && !searchTerm.Any(char.IsWhiteSpace) && (TimeAndDateHelper.IsSpecialInputParsing(searchTerm) || !Regex.IsMatch(searchTerm, @"\d+[\.:/]\d+")))
if (!isEmptySearchInput && results.Count == 0 && Regex.IsMatch(searchTerm, @"\w+[+-]?\d+.*$") && !searchTerm.Any(char.IsWhiteSpace) && (TimeAndDateHelper.IsSpecialInputParsing(searchTerm) || !Regex.IsMatch(searchTerm, @"\d+[\.:/]\d+")))
{
// Without plugin key word show only if message is not hidden by setting
string title = !string.IsNullOrEmpty(lastInputParsingErrorReason) ? Resources.Microsoft_plugin_timedate_ErrorResultValue : Resources.Microsoft_plugin_timedate_ErrorResultTitle;
string message = !string.IsNullOrEmpty(lastInputParsingErrorReason) ? lastInputParsingErrorReason : Resources.Microsoft_plugin_timedate_ErrorResultSubTitle;
// Without plugin key word show only if not hidden by setting
if (isKeywordSearch || !TimeDateSettings.Instance.HideNumberMessageOnGlobalQuery)
{
results.Add(ResultHelper.CreateNumberErrorResult(iconTheme));
results.Add(ResultHelper.CreateNumberErrorResult(iconTheme, title, message));
}
}

View File

@@ -5,7 +5,9 @@
using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.PowerToys.Run.Plugin.TimeDate.Properties;
[assembly: InternalsVisibleTo("Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests")]
@@ -13,6 +15,33 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
{
internal static class TimeAndDateHelper
{
private static readonly Regex _regexSpecialInputFormats = new Regex(@"^.*(::)?(u|ums|ft|oa|exc|exf)[+-]\d");
private static readonly Regex _regexCustomDateTimeFormats = new Regex(@"(?<!\\)(DOW|DIM|WOM|WOY|EAB|WFT|UXT|UMS|OAD|EXC|EXF)");
private static readonly Regex _regexCustomDateTimeDow = new Regex(@"(?<!\\)DOW");
private static readonly Regex _regexCustomDateTimeDim = new Regex(@"(?<!\\)DIM");
private static readonly Regex _regexCustomDateTimeWom = new Regex(@"(?<!\\)WOM");
private static readonly Regex _regexCustomDateTimeWoy = new Regex(@"(?<!\\)WOY");
private static readonly Regex _regexCustomDateTimeEab = new Regex(@"(?<!\\)EAB");
private static readonly Regex _regexCustomDateTimeWft = new Regex(@"(?<!\\)WFT");
private static readonly Regex _regexCustomDateTimeUxt = new Regex(@"(?<!\\)UXT");
private static readonly Regex _regexCustomDateTimeUms = new Regex(@"(?<!\\)UMS");
private static readonly Regex _regexCustomDateTimeOad = new Regex(@"(?<!\\)OAD");
private static readonly Regex _regexCustomDateTimeExc = new Regex(@"(?<!\\)EXC");
private static readonly Regex _regexCustomDateTimeExf = new Regex(@"(?<!\\)EXF");
private const long UnixTimeSecondsMin = -62135596800;
private const long UnixTimeSecondsMax = 253402300799;
private const long UnixTimeMillisecondsMin = -62135596800000;
private const long UnixTimeMillisecondsMax = 253402300799999;
private const long WindowsFileTimeMin = 0;
private const long WindowsFileTimeMax = 2650467707991000000;
private const double OADateMin = -657434.99999999;
private const double OADateMax = 2958465.99999999;
private const double Excel1900DateMin = 1;
private const double Excel1900DateMax = 2958465.99998843;
private const double Excel1904DateMin = 0;
private const double Excel1904DateMax = 2957003.99998843;
/// <summary>
/// Get the format for the time string
/// </summary>
@@ -56,18 +85,25 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
/// Returns the number week in the month (Used code from 'David Morton' from <see href="https://social.msdn.microsoft.com/Forums/vstudio/bf504bba-85cb-492d-a8f7-4ccabdf882cb/get-week-number-for-month"/>)
/// </summary>
/// <param name="date">date</param>
/// <param name="formatSettingFirstDayOfWeek">Setting for the first day in the week.</param>
/// <returns>Number of week in the month</returns>
internal static int GetWeekOfMonth(DateTime date, DayOfWeek formatSettingFirstDayOfWeek)
{
DateTime beginningOfMonth = new DateTime(date.Year, date.Month, 1);
int adjustment = 1; // We count from 1 to 7 and not from 0 to 6
int weekCount = 1;
while (date.Date.AddDays(1).DayOfWeek != formatSettingFirstDayOfWeek)
for (int i = 1; i <= date.Day; i++)
{
date = date.AddDays(1);
DateTime d = new(date.Year, date.Month, i);
// Count week number +1 if day is the first day of a week and not day 1 of the month.
// (If we count on day one of a month we would start the month with week number 2.)
if (i > 1 && d.DayOfWeek == formatSettingFirstDayOfWeek)
{
weekCount += 1;
}
}
return (int)Math.Truncate((double)date.Subtract(beginningOfMonth).TotalDays / 7f) + adjustment;
return weekCount;
}
/// <summary>
@@ -83,40 +119,170 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
return ((date.DayOfWeek + daysInWeek - formatSettingFirstDayOfWeek) % daysInWeek) + adjustment;
}
internal static double ConvertToOleAutomationFormat(DateTime date, OADateFormats type)
{
double v = date.ToOADate();
switch (type)
{
case OADateFormats.Excel1904:
// Excel with base 1904: Adjust by -1462
v -= 1462;
// Date starts at 1/1/1904 = 0
if (Math.Truncate(v) < 0)
{
throw new ArgumentOutOfRangeException("Not a valid Excel date.", innerException: null);
}
return v;
case OADateFormats.Excel1900:
// Excel with base 1900: Adjust by -1 if v < 61
v = v < 61 ? v - 1 : v;
// Date starts at 1/1/1900 = 1
if (Math.Truncate(v) < 1)
{
throw new ArgumentOutOfRangeException("Not a valid Excel date.", innerException: null);
}
return v;
default:
// OLE Automation date: Return as is.
return v;
}
}
/// <summary>
/// Convert input string to a <see cref="DateTime"/> object in local time
/// </summary>
/// <param name="input">String with date/time</param>
/// <param name="timestamp">The new <see cref="DateTime"/> object</param>
/// <param name="inputParsingErrorMsg">Error message shown to the user</param>
/// <returns>True on success, otherwise false</returns>
internal static bool ParseStringAsDateTime(in string input, out DateTime timestamp)
internal static bool ParseStringAsDateTime(in string input, out DateTime timestamp, out string inputParsingErrorMsg)
{
inputParsingErrorMsg = string.Empty;
CompositeFormat errorMessage = CompositeFormat.Parse(Resources.Microsoft_plugin_timedate_InvalidInput_SupportedRange);
if (DateTime.TryParse(input, out timestamp))
{
// Known date/time format
return true;
}
else if (Regex.IsMatch(input, @"^u[\+-]?\d{1,10}$") && long.TryParse(input.TrimStart('u'), out long secondsU))
else if (Regex.IsMatch(input, @"^u[\+-]?\d+$"))
{
// Unix time stamp
// We use long instead of int, because int is too small after 03:14:07 UTC 2038-01-19
var canParse = long.TryParse(input.TrimStart('u'), out var secondsU);
// Value has to be in the range from -62135596800 to 253402300799
if (!canParse || secondsU < UnixTimeSecondsMin || secondsU > UnixTimeSecondsMax)
{
inputParsingErrorMsg = string.Format(CultureInfo.CurrentCulture, errorMessage, Resources.Microsoft_plugin_timedate_Unix, UnixTimeSecondsMin, UnixTimeSecondsMax);
timestamp = new DateTime(1, 1, 1, 1, 1, 1);
return false;
}
timestamp = DateTimeOffset.FromUnixTimeSeconds(secondsU).LocalDateTime;
return true;
}
else if (Regex.IsMatch(input, @"^ums[\+-]?\d{1,13}$") && long.TryParse(input.TrimStart("ums".ToCharArray()), out long millisecondsUms))
else if (Regex.IsMatch(input, @"^ums[\+-]?\d+$"))
{
// Unix time stamp in milliseconds
// We use long instead of int because int is too small after 03:14:07 UTC 2038-01-19
var canParse = long.TryParse(input.TrimStart("ums".ToCharArray()), out var millisecondsUms);
// Value has to be in the range from -62135596800000 to 253402300799999
if (!canParse || millisecondsUms < UnixTimeMillisecondsMin || millisecondsUms > UnixTimeMillisecondsMax)
{
inputParsingErrorMsg = string.Format(CultureInfo.CurrentCulture, errorMessage, Resources.Microsoft_plugin_timedate_Unix_Milliseconds, UnixTimeMillisecondsMin, UnixTimeMillisecondsMax);
timestamp = new DateTime(1, 1, 1, 1, 1, 1);
return false;
}
timestamp = DateTimeOffset.FromUnixTimeMilliseconds(millisecondsUms).LocalDateTime;
return true;
}
else if (Regex.IsMatch(input, @"^ft\d+$") && long.TryParse(input.TrimStart("ft".ToCharArray()), out long secondsFt))
else if (Regex.IsMatch(input, @"^ft\d+$"))
{
var canParse = long.TryParse(input.TrimStart("ft".ToCharArray()), out var secondsFt);
// Windows file time
// Value has to be in the range from 0 to 2650467707991000000
if (!canParse || secondsFt < WindowsFileTimeMin || secondsFt > WindowsFileTimeMax)
{
inputParsingErrorMsg = string.Format(CultureInfo.CurrentCulture, errorMessage, Resources.Microsoft_plugin_timedate_WindowsFileTime, WindowsFileTimeMin, WindowsFileTimeMax);
timestamp = new DateTime(1, 1, 1, 1, 1, 1);
return false;
}
// DateTime.FromFileTime returns as local time.
timestamp = DateTime.FromFileTime(secondsFt);
return true;
}
else if (Regex.IsMatch(input, @"^oa[+-]?\d+[,.0-9]*$"))
{
var canParse = double.TryParse(input.TrimStart("oa".ToCharArray()), out var oADate);
// OLE Automation date
// Input has to be in the range from -657434.99999999 to 2958465.99999999
// DateTime.FromOADate returns as local time.
if (!canParse || oADate < OADateMin || oADate > OADateMax)
{
inputParsingErrorMsg = string.Format(CultureInfo.CurrentCulture, errorMessage, Resources.Microsoft_plugin_timedate_OADate, OADateMin, OADateMax);
timestamp = new DateTime(1, 1, 1, 1, 1, 1);
return false;
}
timestamp = DateTime.FromOADate(oADate);
return true;
}
else if (Regex.IsMatch(input, @"^exc[+-]?\d+[,.0-9]*$"))
{
var canParse = double.TryParse(input.TrimStart("exc".ToCharArray()), out var excDate);
// Excel's 1900 date value
// Input has to be in the range from 1 (0 = Fake date) to 2958465.99998843 and not 60 whole number
// Because of a bug in Excel and the way it behaves before 3/1/1900 we have to adjust all inputs lower than 61 for +1
// DateTime.FromOADate returns as local time.
if (!canParse || excDate < 0 || excDate > Excel1900DateMax)
{
// For the if itself we use 0 as min value that we can show a special message if input is 0.
inputParsingErrorMsg = string.Format(CultureInfo.CurrentCulture, errorMessage, Resources.Microsoft_plugin_timedate_Excel1900, Excel1900DateMin, Excel1900DateMax);
timestamp = new DateTime(1, 1, 1, 1, 1, 1);
return false;
}
if (Math.Truncate(excDate) == 0 || Math.Truncate(excDate) == 60)
{
inputParsingErrorMsg = Resources.Microsoft_plugin_timedate_InvalidInput_FakeExcel1900;
timestamp = new DateTime(1, 1, 1, 1, 1, 1);
return false;
}
excDate = excDate <= 60 ? excDate + 1 : excDate;
timestamp = DateTime.FromOADate(excDate);
return true;
}
else if (Regex.IsMatch(input, @"^exf[+-]?\d+[,.0-9]*$"))
{
var canParse = double.TryParse(input.TrimStart("exf".ToCharArray()), out var exfDate);
// Excel's 1904 date value
// Input has to be in the range from 0 to 2957003.99998843
// Because Excel uses 01/01/1904 as base we need to adjust for +1462
// DateTime.FromOADate returns as local time.
if (!canParse || exfDate < Excel1904DateMin || exfDate > Excel1904DateMax)
{
inputParsingErrorMsg = string.Format(CultureInfo.CurrentCulture, errorMessage, Resources.Microsoft_plugin_timedate_Excel1904, Excel1904DateMin, Excel1904DateMax);
timestamp = new DateTime(1, 1, 1, 1, 1, 1);
return false;
}
timestamp = DateTime.FromOADate(exfDate + 1462);
return true;
}
else
{
timestamp = new DateTime(1, 1, 1, 1, 1, 1);
@@ -125,13 +291,85 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
}
/// <summary>
/// Test if input is special parsing for Unix time, Unix time in milliseconds or File time.
/// Test if input is special parsing for Unix time, Unix time in milliseconds, file time, ...
/// </summary>
/// <param name="input">String with date/time</param>
/// <returns>True if yes, otherwise false</returns>
internal static bool IsSpecialInputParsing(string input)
{
return Regex.IsMatch(input, @"^.*(u|ums|ft)\d");
return _regexSpecialInputFormats.IsMatch(input);
}
/// <summary>
/// Converts a DateTime object based on the format string
/// </summary>
/// <param name="date">Date/time object.</param>
/// <param name="unix">Value for replacing "Unix Time Stamp".</param>
/// <param name="unixMilliseconds">Value for replacing "Unix Time Stamp in milliseconds".</param>
/// <param name="calWeek">Value for relacing calendar week.</param>
/// <param name="eraShortFormat">Era abbreviation.</param>
/// <param name="format">Format definition.</param>
/// <returns>Formated date/time string.</returns>
internal static string ConvertToCustomFormat(DateTime date, long unix, long unixMilliseconds, int calWeek, string eraShortFormat, string format, CalendarWeekRule firstWeekRule, DayOfWeek firstDayOfTheWeek)
{
string result = format;
// DOW: Number of day in week
result = _regexCustomDateTimeDow.Replace(result, GetNumberOfDayInWeek(date, firstDayOfTheWeek).ToString(CultureInfo.CurrentCulture));
// DIM: Days in Month
result = _regexCustomDateTimeDim.Replace(result, DateTime.DaysInMonth(date.Year, date.Month).ToString(CultureInfo.CurrentCulture));
// WOM: Week of Month
result = _regexCustomDateTimeWom.Replace(result, GetWeekOfMonth(date, firstDayOfTheWeek).ToString(CultureInfo.CurrentCulture));
// WOY: Week of Year
result = _regexCustomDateTimeWoy.Replace(result, calWeek.ToString(CultureInfo.CurrentCulture));
// EAB: Era abbreviation
result = _regexCustomDateTimeEab.Replace(result, eraShortFormat);
// WFT: Week of Month
if (_regexCustomDateTimeWft.IsMatch(result))
{
// Special handling as very early dates can't convert.
result = _regexCustomDateTimeWft.Replace(result, date.ToFileTime().ToString(CultureInfo.CurrentCulture));
}
// UXT: Unix time stamp
result = _regexCustomDateTimeUxt.Replace(result, unix.ToString(CultureInfo.CurrentCulture));
// UMS: Unix time stamp milli seconds
result = _regexCustomDateTimeUms.Replace(result, unixMilliseconds.ToString(CultureInfo.CurrentCulture));
// OAD: OLE Automation date
result = _regexCustomDateTimeOad.Replace(result, ConvertToOleAutomationFormat(date, OADateFormats.OLEAutomation).ToString(CultureInfo.CurrentCulture));
// EXC: Excel date value with base 1900
if (_regexCustomDateTimeExc.IsMatch(result))
{
// Special handling as very early dates can't convert.
result = _regexCustomDateTimeExc.Replace(result, ConvertToOleAutomationFormat(date, OADateFormats.Excel1900).ToString(CultureInfo.CurrentCulture));
}
// EXF: Excel date value with base 1904
if (_regexCustomDateTimeExf.IsMatch(result))
{
// Special handling as very early dates can't convert.
result = _regexCustomDateTimeExf.Replace(result, ConvertToOleAutomationFormat(date, OADateFormats.Excel1904).ToString(CultureInfo.CurrentCulture));
}
return result;
}
/// <summary>
/// Test a string for our custom date and time format syntax
/// </summary>
/// <param name="str">String to test.</param>
/// <returns>True if yes and otherwise false</returns>
internal static bool StringContainsCustomFormatSyntax(string str)
{
return _regexCustomDateTimeFormats.IsMatch(str);
}
/// <summary>
@@ -190,4 +428,14 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
Date,
DateTime,
}
/// <summary>
/// Different versions of Date formats based on OLE Automation date
/// </summary>
internal enum OADateFormats
{
OLEAutomation,
Excel1900,
Excel1904,
}
}

View File

@@ -61,6 +61,11 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
/// </summary>
internal bool HideNumberMessageOnGlobalQuery { get; private set; }
/// <summary>
/// Gets a value containing the custom format definitions
/// </summary>
internal List<string> CustomFormats { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="TimeDateSettings"/> class.
/// Private constructor to make sure there is never more than one instance of this class
@@ -100,29 +105,6 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
{
var optionList = new List<PluginAdditionalOption>
{
new PluginAdditionalOption()
{
Key = nameof(CalendarFirstWeekRule),
DisplayLabel = Resources.Microsoft_plugin_timedate_SettingFirstWeekRule,
DisplayDescription = Resources.Microsoft_plugin_timedate_SettingFirstWeekRule_Description,
PluginOptionType = PluginAdditionalOption.AdditionalOptionType.Combobox,
ComboBoxItems = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(Resources.Microsoft_plugin_timedate_Setting_UseSystemSetting, "-1"),
new KeyValuePair<string, string>(Resources.Microsoft_plugin_timedate_SettingFirstWeekRule_FirstDay, "0"),
new KeyValuePair<string, string>(Resources.Microsoft_plugin_timedate_SettingFirstWeekRule_FirstFullWeek, "1"),
new KeyValuePair<string, string>(Resources.Microsoft_plugin_timedate_SettingFirstWeekRule_FirstFourDayWeek, "2"),
},
ComboBoxValue = -1,
},
new PluginAdditionalOption()
{
Key = nameof(FirstDayOfWeek),
DisplayLabel = Resources.Microsoft_plugin_timedate_SettingFirstDayOfWeek,
PluginOptionType = PluginAdditionalOption.AdditionalOptionType.Combobox,
ComboBoxItems = GetSortedListForWeekDaySetting(),
ComboBoxValue = -1,
},
new PluginAdditionalOption()
{
Key = nameof(OnlyDateTimeNowGlobal),
@@ -150,6 +132,38 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
DisplayLabel = Resources.Microsoft_plugin_timedate_SettingHideNumberMessageOnGlobalQuery,
Value = false,
},
new PluginAdditionalOption()
{
Key = nameof(CalendarFirstWeekRule),
DisplayLabel = Resources.Microsoft_plugin_timedate_SettingFirstWeekRule,
DisplayDescription = Resources.Microsoft_plugin_timedate_SettingFirstWeekRule_Description,
PluginOptionType = PluginAdditionalOption.AdditionalOptionType.Combobox,
ComboBoxItems = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(Resources.Microsoft_plugin_timedate_Setting_UseSystemSetting, "-1"),
new KeyValuePair<string, string>(Resources.Microsoft_plugin_timedate_SettingFirstWeekRule_FirstDay, "0"),
new KeyValuePair<string, string>(Resources.Microsoft_plugin_timedate_SettingFirstWeekRule_FirstFullWeek, "1"),
new KeyValuePair<string, string>(Resources.Microsoft_plugin_timedate_SettingFirstWeekRule_FirstFourDayWeek, "2"),
},
ComboBoxValue = -1,
},
new PluginAdditionalOption()
{
Key = nameof(FirstDayOfWeek),
DisplayLabel = Resources.Microsoft_plugin_timedate_SettingFirstDayOfWeek,
PluginOptionType = PluginAdditionalOption.AdditionalOptionType.Combobox,
ComboBoxItems = GetSortedListForWeekDaySetting(),
ComboBoxValue = -1,
},
new PluginAdditionalOption()
{
Key = nameof(CustomFormats),
PluginOptionType = PluginAdditionalOption.AdditionalOptionType.MultilineTextbox,
DisplayLabel = Resources.Microsoft_plugin_timedate_Setting_CustomFormats,
DisplayDescription = string.Format(CultureInfo.CurrentCulture, Resources.Microsoft_plugin_timedate_Setting_CustomFormatsDescription.ToString(), "DOW", "DIM", "WOM", "WOY", "EAB", "WFT", "UXT", "UMS", "OAD", "EXC", "EXF", "UTC:"),
PlaceholderText = "MyFormat=dd-MMM-yyyy\rMySecondFormat=dddd (Da\\y nu\\mber: DOW)\rMyUtcFormat=UTC:hh:mm:ss",
TextValue = string.Empty,
},
};
return optionList;
@@ -172,6 +186,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
TimeWithSeconds = GetSettingOrDefault(settings, nameof(TimeWithSeconds));
DateWithWeekday = GetSettingOrDefault(settings, nameof(DateWithWeekday));
HideNumberMessageOnGlobalQuery = GetSettingOrDefault(settings, nameof(HideNumberMessageOnGlobalQuery));
CustomFormats = GetMultilineTextSettingOrDefault(settings, nameof(CustomFormats));
}
/// <summary>
@@ -204,6 +219,21 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
return option?.ComboBoxValue ?? GetAdditionalOptions().First(x => x.Key == name).ComboBoxValue;
}
/// <summary>
/// Return the combobox value of the given settings list with the given name.
/// </summary>
/// <param name="settings">The object that contain all settings.</param>
/// <param name="name">The name of the setting.</param>
/// <returns>A settings value.</returns>
private static List<string> GetMultilineTextSettingOrDefault(PowerLauncherPluginSettings settings, string name)
{
var option = settings?.AdditionalOptions?.FirstOrDefault(x => x.Key == name);
// If a setting isn't available, we use the value defined in the method GetAdditionalOptions() as fallback.
// We can use First() instead of FirstOrDefault() because the values must exist. Otherwise, we made a mistake when defining the settings.
return option?.TextValueAsMultilineList ?? GetAdditionalOptions().First(x => x.Key == name).TextValueAsMultilineList;
}
/// <summary>
/// Returns a sorted list of values for the combo box of 'first day of week' setting.
/// The list is sorted based on the current system culture setting.

View File

@@ -150,6 +150,15 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Days in month.
/// </summary>
internal static string Microsoft_plugin_timedate_DaysInMonth {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_DaysInMonth", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Era.
/// </summary>
@@ -169,7 +178,25 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
/// <summary>
/// Looks up a localized string similar to Valid prefixes: &apos;u&apos; for Unix Timestamp, &apos;ums&apos; for Unix Timestamp in milliseconds, &apos;ft&apos; for Windows file time.
/// Looks up a localized string similar to Failed to convert into custom format:.
/// </summary>
internal static string Microsoft_plugin_timedate_ErrorConvertCustomFormat {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_ErrorConvertCustomFormat", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not a valid Windows file time.
/// </summary>
internal static string Microsoft_plugin_timedate_ErrorConvertWft {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_ErrorConvertWft", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Valid prefixes: &apos;u&apos; for Unix Timestamp, &apos;ums&apos; for Unix Timestamp in milliseconds, &apos;ft&apos; for Windows file time, &apos;oa&apos; for OLE Automation date, &apos;exc&apos; for Excel&apos;s 1900 date value, &apos;exf&apos; for Excel&apos;s 1904 date value.
/// </summary>
internal static string Microsoft_plugin_timedate_ErrorResultSubTitle {
get {
@@ -178,7 +205,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
/// <summary>
/// Looks up a localized string similar to Error: Invalid number input.
/// Looks up a localized string similar to Error: Invalid input.
/// </summary>
internal static string Microsoft_plugin_timedate_ErrorResultTitle {
get {
@@ -186,6 +213,33 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Error: Invalid number.
/// </summary>
internal static string Microsoft_plugin_timedate_ErrorResultValue {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_ErrorResultValue", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Excel&apos;s 1900 date value.
/// </summary>
internal static string Microsoft_plugin_timedate_Excel1900 {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_Excel1900", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Excel&apos;s 1904 date value.
/// </summary>
internal static string Microsoft_plugin_timedate_Excel1904 {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_Excel1904", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Date and time in filename-compatible format.
/// </summary>
@@ -204,6 +258,33 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Invalid custom format:.
/// </summary>
internal static string Microsoft_plugin_timedate_InvalidCustomFormat {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_InvalidCustomFormat", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot parse the input as Excel&apos;s 1900 date value because it is a fake date. (In Excel 0 stands for 0/1/1900 and this date doesn&apos;t exist. And 60 stands for 2/29/1900 and this date only exists in Excel for compatibility with Lotus 123.).
/// </summary>
internal static string Microsoft_plugin_timedate_InvalidInput_FakeExcel1900 {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_InvalidInput_FakeExcel1900", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Your input for {0} is outside the range from {1} to {2}..
/// </summary>
internal static string Microsoft_plugin_timedate_InvalidInput_SupportedRange {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_InvalidInput_SupportedRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ISO 8601.
/// </summary>
@@ -240,6 +321,15 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Leap year.
/// </summary>
internal static string Microsoft_plugin_timedate_LeapYear {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_LeapYear", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Millisecond.
/// </summary>
@@ -285,6 +375,15 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Not a leap year.
/// </summary>
internal static string Microsoft_plugin_timedate_NoLeapYear {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_NoLeapYear", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Now.
/// </summary>
@@ -303,6 +402,15 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to OLE Automation Date.
/// </summary>
internal static string Microsoft_plugin_timedate_OADate {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_OADate", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Provides time and date values for the system time or a custom time stamp (e.g.&apos;{0}&apos;, &apos;{1}&apos;, &apos;{2}&apos;, &apos;{3}&apos;).
/// </summary>
@@ -366,6 +474,42 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Date and time; Time and Date; Custom format.
/// </summary>
internal static string Microsoft_plugin_timedate_SearchTagCustom {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagCustom", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Current date and time; Current time and date; Now; Custom format.
/// </summary>
internal static string Microsoft_plugin_timedate_SearchTagCustomNow {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagCustomNow", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Date and time UTC; Time UTC and Date; Custom UTC format.
/// </summary>
internal static string Microsoft_plugin_timedate_SearchTagCustomUtc {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagCustomUtc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Current date and time UTC; Current time UTC and date; Now UTC; Custom UTC format.
/// </summary>
internal static string Microsoft_plugin_timedate_SearchTagCustomUtcNow {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagCustomUtcNow", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Date.
/// </summary>
@@ -447,6 +591,24 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Custom formats.
/// </summary>
internal static string Microsoft_plugin_timedate_Setting_CustomFormats {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_Setting_CustomFormats", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use date and time string format syntax and {0} (Day of Week), {1} (Days in Month), {2} (Week of Month), {3} (Week of the year), {4} (Era abbreviation), {5} (Windows File Time), {6} (Unix Time), {7} (Unix Time in milliseconds), {8} (OLE Automation date), {9} (Excel&apos;s 1900 based date value), {10} (Excel&apos;s 1904 based date value). If the format starts with {11}, then Universal Time (UTC) is used. (Use a backslash to escape format sequences and the backslash character as text.).
/// </summary>
internal static string Microsoft_plugin_timedate_Setting_CustomFormatsDescription {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_Setting_CustomFormatsDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use system setting.
/// </summary>

View File

@@ -156,10 +156,13 @@
<value>Era abbreviation</value>
</data>
<data name="Microsoft_plugin_timedate_ErrorResultSubTitle" xml:space="preserve">
<value>Valid prefixes: 'u' for Unix Timestamp, 'ums' for Unix Timestamp in milliseconds, 'ft' for Windows file time</value>
<value>Valid prefixes: 'u' for Unix Timestamp, 'ums' for Unix Timestamp in milliseconds, 'ft' for Windows file time, 'oa' for OLE Automation date, 'exc' for Excel's 1900 date value, 'exf' for Excel's 1904 date value</value>
</data>
<data name="Microsoft_plugin_timedate_ErrorResultTitle" xml:space="preserve">
<value>Error: Invalid number input</value>
<value>Error: Invalid input</value>
</data>
<data name="Microsoft_plugin_timedate_ErrorResultValue" xml:space="preserve">
<value>Error: Invalid number</value>
</data>
<data name="Microsoft_plugin_timedate_Hour" xml:space="preserve">
<value>Hour</value>
@@ -243,10 +246,26 @@
<value>Date and time; Time and Date</value>
<comment>Don't change order</comment>
</data>
<data name="Microsoft_plugin_timedate_SearchTagCustom" xml:space="preserve">
<value>Date and time; Time and Date; Custom format</value>
<comment>Don't change order</comment>
</data>
<data name="Microsoft_plugin_timedate_SearchTagCustomUtc" xml:space="preserve">
<value>Date and time UTC; Time UTC and Date; Custom UTC format</value>
<comment>Don't change order</comment>
</data>
<data name="Microsoft_plugin_timedate_SearchTagFormatNow" xml:space="preserve">
<value>Current date and time; Current time and date; Now</value>
<comment>Don't change order</comment>
</data>
<data name="Microsoft_plugin_timedate_SearchTagCustomNow" xml:space="preserve">
<value>Current date and time; Current time and date; Now; Custom format</value>
<comment>Don't change order</comment>
</data>
<data name="Microsoft_plugin_timedate_SearchTagCustomUtcNow" xml:space="preserve">
<value>Current date and time UTC; Current time UTC and date; Now UTC; Custom UTC format</value>
<comment>Don't change order</comment>
</data>
<data name="Microsoft_plugin_timedate_SearchTagTime" xml:space="preserve">
<value>Time</value>
<comment>Don't change order</comment>
@@ -262,6 +281,9 @@
<data name="Microsoft_plugin_timedate_Second" xml:space="preserve">
<value>Second</value>
</data>
<data name="Microsoft_plugin_timedate_InvalidCustomFormat" xml:space="preserve">
<value>Invalid custom format:</value>
</data>
<data name="Microsoft_plugin_timedate_SettingDateWithWeekday" xml:space="preserve">
<value>Show date with weekday and name of month</value>
</data>
@@ -360,4 +382,42 @@
<data name="Microsoft_plugin_timedate_Setting_UseSystemSetting" xml:space="preserve">
<value>Use system setting</value>
</data>
<data name="Microsoft_plugin_timedate_Setting_CustomFormats" xml:space="preserve">
<value>Custom formats</value>
</data>
<data name="Microsoft_plugin_timedate_Setting_CustomFormatsDescription" xml:space="preserve">
<value>Use date and time string format syntax and {0} (Day of Week), {1} (Days in Month), {2} (Week of Month), {3} (Week of the year), {4} (Era abbreviation), {5} (Windows File Time), {6} (Unix Time), {7} (Unix Time in milliseconds), {8} (OLE Automation date), {9} (Excel's 1900 based date value), {10} (Excel's 1904 based date value). If the format starts with {11}, then Universal Time (UTC) is used. (Use a backslash to escape format sequences and the backslash character as text.)</value>
<comment>The {n} parts are place holders and get replaced in the code.</comment>
</data>
<data name="Microsoft_plugin_timedate_ErrorConvertCustomFormat" xml:space="preserve">
<value>Failed to convert into custom format:</value>
</data>
<data name="Microsoft_plugin_timedate_ErrorConvertWft" xml:space="preserve">
<value>Not a valid Windows file time</value>
</data>
<data name="Microsoft_plugin_timedate_InvalidInput_SupportedRange" xml:space="preserve">
<value>Your input for {0} is outside the range from {1} to {2}.</value>
<comment>The placeholder will be replace in code.</comment>
</data>
<data name="Microsoft_plugin_timedate_OADate" xml:space="preserve">
<value>OLE Automation Date</value>
</data>
<data name="Microsoft_plugin_timedate_Excel1900" xml:space="preserve">
<value>Excel's 1900 date value</value>
</data>
<data name="Microsoft_plugin_timedate_InvalidInput_FakeExcel1900" xml:space="preserve">
<value>Cannot parse the input as Excel's 1900 date value because it is a fake date. (In Excel 0 stands for 0/1/1900 and this date doesn't exist. And 60 stands for 2/29/1900 and this date only exists in Excel for compatibility with Lotus 123.)</value>
</data>
<data name="Microsoft_plugin_timedate_Excel1904" xml:space="preserve">
<value>Excel's 1904 date value</value>
</data>
<data name="Microsoft_plugin_timedate_LeapYear" xml:space="preserve">
<value>Leap year</value>
</data>
<data name="Microsoft_plugin_timedate_NoLeapYear" xml:space="preserve">
<value>Not a leap year</value>
</data>
<data name="Microsoft_plugin_timedate_DaysInMonth" xml:space="preserve">
<value>Days in month</value>
</data>
</root>

View File

@@ -295,7 +295,7 @@
"Areas": [ "AreaEaseOfAccess" ],
"Type": "AppSettingsApp",
"AltNames": [ "TouchFeedback" ],
"Command": "ms-settings:easeofaccess-MousePointer"
"Command": "ms-settings:easeofaccess-mousepointer"
},
{
"Name": "Display",

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<AssemblyTitle>PowerToys.Run</AssemblyTitle>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
@@ -40,4 +39,4 @@
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
@@ -72,4 +71,4 @@
</None>
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
@@ -54,4 +53,4 @@
<ProjectReference Include="..\common\PreviewHandlerCommon.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
@@ -38,4 +37,4 @@
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
@@ -39,4 +38,4 @@
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
@@ -45,4 +44,4 @@
<ProjectReference Include="..\Common\PreviewHandlerCommon.csproj" />
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
@@ -42,4 +41,4 @@
<ProjectReference Include="..\Common\PreviewHandlerCommon.csproj" />
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
@@ -80,4 +79,4 @@
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
</Project>
</Project>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\Common.SelfContained.props" />
<PropertyGroup>
<Description>PowerToys Settings UI Library</Description>
<AssemblyName>PowerToys.Settings.UI.Lib</AssemblyName>

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>

View File

@@ -28,18 +28,15 @@ namespace Microsoft.PowerToys.Settings.UI
var bootTime = new System.Diagnostics.Stopwatch();
bootTime.Start();
this.Activated += Window_Activated_SetIcon;
App.ThemeService.ThemeChanged += OnThemeChanged;
App.ThemeService.ApplyTheme();
ShellPage.SetElevationStatus(App.IsElevated);
ShellPage.SetIsUserAnAdmin(App.IsUserAnAdmin);
// Set window icon
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
appWindow.SetIcon("Assets\\Settings\\icon.ico");
var placement = WindowHelper.DeserializePlacementOrDefault(hWnd);
if (createHidden)
{
@@ -221,6 +218,15 @@ namespace Microsoft.PowerToys.Settings.UI
App.ThemeService.ThemeChanged -= OnThemeChanged;
}
private void Window_Activated_SetIcon(object sender, WindowActivatedEventArgs args)
{
// Set window icon
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
appWindow.SetIcon("Assets\\Settings\\icon.ico");
}
private void Window_Activated(object sender, WindowActivatedEventArgs args)
{
if (args.WindowActivationState != WindowActivationState.Deactivated)

View File

@@ -41,11 +41,10 @@ namespace Microsoft.PowerToys.Settings.UI
this.InitializeComponent();
// Set window icon
_hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
_windowId = Win32Interop.GetWindowIdFromWindow(_hWnd);
_appWindow = AppWindow.GetFromWindowId(_windowId);
_appWindow.SetIcon("Assets\\Settings\\icon.ico");
this.Activated += Window_Activated_SetIcon;
OverlappedPresenter presenter = _appWindow.Presenter as OverlappedPresenter;
presenter.IsMinimizable = false;
@@ -110,6 +109,12 @@ namespace Microsoft.PowerToys.Settings.UI
}
}
private void Window_Activated_SetIcon(object sender, WindowActivatedEventArgs args)
{
// Set window icon
_appWindow.SetIcon("Assets\\Settings\\icon.ico");
}
private void OobeWindow_SizeChanged(object sender, WindowSizeChangedEventArgs args)
{
var dpi = NativeMethods.GetDpiForWindow(_hWnd);