Merge remote-tracking branch 'origin/main' into dev/snickler/net8-upgrade

This commit is contained in:
Jeremy Sinclair 2023-11-08 07:57:09 -05:00
commit 163066db6e
67 changed files with 1705 additions and 1281 deletions

View File

@ -14,7 +14,9 @@ https://www.regexplanet.com/advanced/perl/) yours before committing to verify it
* well-formed pattern. * well-formed pattern.
If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it, If you can write a [pattern](
https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
) that would match it,
try adding it to the `patterns.txt` file. try adding it to the `patterns.txt` file.
Patterns are Perl 5 Regular Expressions - you can [test]( Patterns are Perl 5 Regular Expressions - you can [test](

View File

@ -9,4 +9,5 @@ sdl
ssh ssh
ubuntu ubuntu
unuing unuing
workarounds
wil wil

View File

@ -0,0 +1,11 @@
etw
filetime
flyouts
lnks
reparented
screenshots
SIDs
subkeys
TApp
websites
wmi

View File

@ -1,23 +1,36 @@
# marker to ignore all code on line # marker to ignore all code on line
^.*/\* #no-spell-check-line \*/.*$ ^.*/\* #no-spell-check-line \*/.*$
# marker for ignoring a comment to the end of the line # marker to ignore all code on line
// #no-spell-check.*$ ^.*\bno-spell-check(?:-line|)(?:\s.*|)$
# https://cspell.org/configuration/document-settings/
# cspell inline
^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b
# patch hunk comments # patch hunk comments
^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .* ^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .*
# git index header # git index header
index [0-9a-z]{7,40}\.\.[0-9a-z]{7,40} index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
# file permissions
['"`\s][-bcdLlpsw](?:[-r][-w][-Ssx]){2}[-r][-w][-SsTtx]\+?['"`\s]
# css url wrappings
\burl\([^)]+\)
# cid urls # cid urls
(['"])cid:.*?\g{-1} (['"])cid:.*?\g{-1}
# data url in parens # data url in parens
\(data:[^)]*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\) \(data:(?:[^) ][^)]*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\)
# data url in quotes # data url in quotes
([`'"])data:.*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1} ([`'"])data:(?:[^ `'"].*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
# data url # data url
data:[-a-zA-Z=;:/0-9+]*,\S* data:[-a-zA-Z=;:/0-9+]*,\S*
# https/http/file urls
#(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]
# mailto urls # mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,} mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
@ -35,6 +48,9 @@ magnet:[?=:\w]+
# asciinema # asciinema
\basciinema\.org/a/[0-9a-zA-Z]+ \basciinema\.org/a/[0-9a-zA-Z]+
# asciinema v2
^\[\d+\.\d+, "[io]", ".*"\]$
# apple # apple
\bdeveloper\.apple\.com/[-\w?=/]+ \bdeveloper\.apple\.com/[-\w?=/]+
# Apple music # Apple music
@ -89,7 +105,7 @@ vpc-\w+
# Google Drive # Google Drive
\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]* \bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]*
# Google Groups # Google Groups
\bgroups\.google\.com/(?:(?:forum/#!|d/)(?:msg|topics?|searchin)|a)/[^/\s"]+/[-a-zA-Z0-9$]+(?:/[-a-zA-Z0-9]+)* \bgroups\.google\.com(?:/[a-z]+/(?:#!|)[^/\s"]+)*
# Google Maps # Google Maps
\bmaps\.google\.com/maps\?[\w&;=]* \bmaps\.google\.com/maps\?[\w&;=]*
# Google themes # Google themes
@ -117,6 +133,8 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|) (?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
# GitHub SHAs # GitHub SHAs
\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b \bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b
# GitHub SHA refs
\[([0-9a-f]+)\]\(https://(?:www\.|)github.com/[-\w]+/[-\w]+/commit/\g{-1}[0-9a-f]*
# GitHub wiki # GitHub wiki
\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b \bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b
# githubusercontent # githubusercontent
@ -128,9 +146,9 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
# git.io # git.io
\bgit\.io/[0-9a-zA-Z]+ \bgit\.io/[0-9a-zA-Z]+
# GitHub JSON # GitHub JSON
"node_id": "[-a-zA-Z=;:/0-9+]*" "node_id": "[-a-zA-Z=;:/0-9+_]*"
# Contributor # Contributor
\[[^\]]+\]\(https://github\.com/[^/\s"]+\) \[[^\]]+\]\(https://github\.com/[^/\s"]+/?\)
# GHSA # GHSA
GHSA(?:-[0-9a-z]{4}){3} GHSA(?:-[0-9a-z]{4}){3}
@ -143,8 +161,8 @@ GHSA(?:-[0-9a-z]{4}){3}
# GitLab commits # GitLab commits
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b \bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
# binanace # binance
accounts.binance.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]* accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
# bitbucket diff # bitbucket diff
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+ \bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+
@ -280,9 +298,9 @@ slack://[a-zA-Z0-9?&=]+
\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+ \bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+
# ipfs protocol # ipfs protocol
ipfs://[0-9a-z]* ipfs://[0-9a-zA-Z]{3,}
# ipfs url # ipfs url
/ipfs/[0-9a-z]* /ipfs/[0-9a-zA-Z]{3,}
# w3 # w3
\bw3\.org/[-0-9a-zA-Z/#.]+ \bw3\.org/[-0-9a-zA-Z/#.]+
@ -359,14 +377,22 @@ ipfs://[0-9a-z]*
# tinyurl # tinyurl
\btinyurl\.com/\w+ \btinyurl\.com/\w+
# codepen
\bcodepen\.io/[\w/]+
# registry.npmjs.org
\bregistry\.npmjs\.org/(?:@[^/"']+/|)[^/"']+/-/[-\w@.]+
# getopts # getopts
\bgetopts\s+(?:"[^"]+"|'[^']+') \bgetopts\s+(?:"[^"]+"|'[^']+')
# ANSI color codes # ANSI color codes
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m (?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m
# URL escaped characters # URL escaped characters
\%[0-9A-F][A-F] \%[0-9A-F][A-F]
# lower URL escaped characters
\%[0-9a-f][a-f](?=[a-z]{2,})
# IPv6 # IPv6
\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b \b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
# c99 hex digits (not the full format, just one I've seen) # c99 hex digits (not the full format, just one I've seen)
@ -376,7 +402,7 @@ ipfs://[0-9a-z]*
# sha # sha
sha\d+:[0-9]*[a-f]{3,}[0-9a-f]* sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
# sha-... -- uses a fancy capture # sha-... -- uses a fancy capture
(['"]|")[0-9a-f]{40,}\g{-1} (\\?['"]|")[0-9a-f]{40,}\g{-1}
# hex runs # hex runs
\b[0-9a-fA-F]{16,}\b \b[0-9a-fA-F]{16,}\b
# hex in url queries # hex in url queries
@ -391,18 +417,21 @@ sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
# Well known gpg keys # Well known gpg keys
.well-known/openpgpkey/[\w./]+ .well-known/openpgpkey/[\w./]+
# pki
-----BEGIN.*-----END
# uuid: # uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b \b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hex digits including css/html color classes: # hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b (?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
# integrity # integrity
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}" integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1}
# https://www.gnu.org/software/groff/manual/groff.html # https://www.gnu.org/software/groff/manual/groff.html
# man troff content # man troff content
\\f[BCIPR] \\f[BCIPR]
# ' # '/"
\\\(aq \\\([ad]q
# .desktop mime types # .desktop mime types
^MimeTypes?=.*$ ^MimeTypes?=.*$
@ -411,21 +440,33 @@ integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
# Localized .desktop content # Localized .desktop content
Name\[[^\]]+\]=.* Name\[[^\]]+\]=.*
# IServiceProvider # IServiceProvider / isAThing
\bI(?=(?:[A-Z][a-z]{2,})+\b) \b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b)
# crypt # crypt
"\$2[ayb]\$.{56}" (['"])\$2[ayb]\$.{56}\g{-1}
# scrypt / argon # scrypt / argon
\$(?:scrypt|argon\d+[di]*)\$\S+ \$(?:scrypt|argon\d+[di]*)\$\S+
# Input to GitHub JSON # go.sum
content: "[-a-zA-Z=;:/0-9+]*=" \bh1:\S+
# Python stringprefix / binaryprefix # scala modules
#("[^"]+"\s*%%?\s*){2,3}"[^"]+"
# Input to GitHub JSON
content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1}
# This does not cover multiline strings, if your repository has them,
# you'll want to remove the `(?=.*?")` suffix.
# The `(?=.*?")` suffix should limit the false positives rate
# printf
#%(?:(?:(?:hh?|ll?|[jzt])?[diuoxn]|l?[cs]|L?[fega]|p)(?=[a-z]{2,})|(?:X|L?[FEGA]|p)(?=[a-zA-Z]{2,}))(?=[_a-zA-Z]+\b)(?!%)(?=.*?['"])
# Python string prefix / binary prefix
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings # Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}) (?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?=[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
# Regular expressions for (P|p)assword # Regular expressions for (P|p)assword
\([A-Z]\|[a-z]\)[a-z]+ \([A-Z]\|[a-z]\)[a-z]+
@ -441,16 +482,35 @@ content: "[-a-zA-Z=;:/0-9+]*="
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$) ^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
# javascript replace regex # javascript replace regex
\.replace\(/[^/\s"]*/[gim]*\s*, \.replace\(/[^/\s"]*/[gim]*\s*,
# assign regex
= /[^*]*?(?:[a-z]{3,}|[A-Z]{3,}|[A-Z][a-z]{2,}).*/
# perl regex test
[!=]~ (?:/.*/|m\{.*?\}|m<.*?>|m([|!/@#,;']).*?\g{-1})
# perl qr regex
(?<!\$)\bqr(?:\{.*?\}|<.*?>|\(.*?\)|([|!/@#,;']).*?\g{-1})
# Go regular expressions # Go regular expressions
regexp?\.MustCompile\(`[^`]*`\) regexp?\.MustCompile\(`[^`]*`\)
# regex choice
\(\?:[^)]+\|[^)]+\)
# proto
^\s*(\w+)\s\g{-1} =
# sed regular expressions # sed regular expressions
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2} sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
# node packages
(["'])\@[^/'" ]+/[^/'" ]+\g{-1}
# go install # go install
go install(?:\s+[a-z]+\.[-@\w/.]+)+ go install(?:\s+[a-z]+\.[-@\w/.]+)+
# jetbrains schema https://youtrack.jetbrains.com/issue/RSRP-489571
urn:shemas-jetbrains-com
# kubernetes pod status lists # kubernetes pod status lists
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+ \w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
@ -462,19 +522,47 @@ go install(?:\s+[a-z]+\.[-@\w/.]+)+
-[0-9a-f]{10}-\w{5}\s -[0-9a-f]{10}-\w{5}\s
# posthog secrets # posthog secrets
posthog\.init\((['"])phc_[^"',]+\g{-1}, ([`'"])phc_[^"',]+\g{-1}
# xcode # xcode
# xcodeproject scenes # xcodeproject scenes
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}" (?:Controller|destination|ID|id)="\w{3}-\w{2}-\w{3}"
# xcode api botches # xcode api botches
customObjectInstantitationMethod customObjectInstantitationMethod
# configure flags
.* \| --\w{2,}.*?(?=\w+\s\w+)
# font awesome classes # font awesome classes
\.fa-[-a-z0-9]+ \.fa-[-a-z0-9]+
# bearer auth
(['"])Bear[e][r] .*?\g{-1}
# basic auth
(['"])Basic [-a-zA-Z=;:/0-9+]{3,}\g{-1}
# base64 encoded content
([`'"])[-a-zA-Z=;:/0-9+]+=\g{-1}
# base64 encoded content in xml/sgml
>[-a-zA-Z=;:/0-9+]+=</
# base64 encoded content, possibly wrapped in mime
(?:^|[\s=;:?])[-a-zA-Z=;:/0-9+]{50,}(?:[\s=;:?]|$)
# encoded-word
=\?[-a-zA-Z0-9"*%]+\?[BQ]\?[^?]{0,75}\?=
# Time Zones
\b(?:Africa|Atlantic|America|Antarctica|Asia|Australia|Europe|Indian|Pacific)(?:/\w+)+
# linux kernel info
^(?:bugs|flags|Features)\s+:.*
# systemd mode
systemd.*?running in system mode \([-+].*\)$
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally ) # Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review - # grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into: # Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
@ -485,32 +573,57 @@ customObjectInstantitationMethod
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])* (?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
# Non-English # Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]* [a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
# highlighted letters
\[[A-Z]\][a-z]+
# French # French
# This corpus only had capital letters, but you probably want lowercase ones as well. # This corpus only had capital letters, but you probably want lowercase ones as well.
\b[LN]'+[a-z]{2,}\b \b[LN]'+[a-z]{2,}\b
# latex # latex (check-spelling >= 0.0.22)
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+) \\\w{2,}\{
# eslint
"varsIgnorePattern": ".+"
# Windows short paths
[/\\][^/\\]{5,6}~\d{1,2}[/\\]
# in check-spelling@v0.0.22+, printf markers aren't automatically consumed
# printf markers
#(?<!\\)\\[nrt](?=[a-z]{2,})
# alternate markers if you run into latex and friends
#(?<!\\)\\[nrt](?=[a-z]{2,})(?=.*['"`])
# apache
a2(?:en|dis)
# weak e-tag
W/"[^"]+"
# the negative lookahead here is to allow catching 'templatesz' as a misspelling # the negative lookahead here is to allow catching 'templatesz' as a misspelling
# but to otherwise recognize a Windows path with \templates\foo.template or similar: # but to otherwise recognize a Windows path with \templates\foo.template or similar:
\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z]) #\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z])
# ignore long runs of a single character: # ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b \b([A-Za-z])\g{-1}{3,}\b
# Note that the next example is no longer necessary if you are using
# to match a string starting with a `#`, use a character-class:
[#]backwards
# version suffix <word>v# # version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_])) (?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# Compiler flags (Scala)
(?:^|[\t ,>"'`=(])-J-[DPWXY](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}) # Compiler flags (Unix, Java/Scala)
# Compiler flags # Use if you have things like `-Pdocker` and want to treat them as `docker`
#(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}) #(?:^|[\t ,>"'`=(])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags (Windows / PowerShell)
# This is a subset of the more general compiler flags pattern.
# It avoids matching `-Path` to prevent it from being treated as `ath`
#(?:^|[\t ,"'`=(])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}))
# Compiler flags (linker) # Compiler flags (linker)
,-B ,-B
# curl arguments # curl arguments
\b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)* \b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# set arguments # set arguments

View File

@ -10,68 +10,87 @@
(?:^|/)FilePreviewCommon/Assets/Monaco/monacoSpecialLanguages.js (?:^|/)FilePreviewCommon/Assets/Monaco/monacoSpecialLanguages.js
(?:^|/)monacoSRC/ (?:^|/)monacoSRC/
(?:^|/)package(?:-lock|)\.json$ (?:^|/)package(?:-lock|)\.json$
(?:^|/)Pipfile$
(?:^|/)power-rename-ui-flags$
(?:^|/)pyproject.toml
(?:^|/)requirements(?:-dev|-doc|-test|)\.txt$
(?:^|/)timezones\.json$ (?:^|/)timezones\.json$
(?:^|/)vendor/ (?:^|/)vendor/
(?:^|/)WindowsSettings\.json$ (?:^|/)WindowsSettings\.json$
/package(?:-lock|)\.json$ /images/launcher/[^/]+$
/pinyindb/ /TestFiles/
/settings-html/ [^/]\.gcode$
[/.][a-z]{2}(?:-[a-zA-Z]{2}|)\. [^/]\.rgs$
\.a$ \.a$
\.ai$ \.ai$
\.all-contributorsrc$
\.avi$ \.avi$
\.bmp$ \.bmp$
\.bz2$ \.bz2$
\.cer$
\.class$ \.class$
\.coveragerc$
\.crl$
\.crt$ \.crt$
\.dat$ \.csr$
\.dll$ \.dll$
\.docx?$ \.docx?$
\.drawio$ \.drawio$
\.DS_Store$ \.DS_Store$
\.eot$ \.eot$
\.eps$
\.exe$ \.exe$
\.filters$ \.filters$
\.gcode$
\.gif$ \.gif$
\.git-blame-ignore-revs$
\.gitattributes$ \.gitattributes$
\.gitignore$ \.gitkeep$
\.graffle$ \.graffle$
\.gz$ \.gz$
\.icns$ \.icns$
\.ico$ \.ico$
\.ipynb$
\.jar$ \.jar$
\.jks$ \.jks$
\.jpe?g$ \.jpe?g$
\.key$ \.key$
\.lcl$
\.lib$ \.lib$
\.lock$ \.lock$
\.map$ \.map$
\.min\.. \.min\..
\.mo$
\.mod$ \.mod$
\.mp[34]$ \.mp[34]$
\.o$ \.o$
\.ocf$ \.ocf$
\.otf$ \.otf$
\.p12$
\.parquet$
\.pdf$ \.pdf$
\.pem$ \.pem$
\.PNG$ \.pfx$
\.png$ \.png$
\.psd$ \.psd$
\.pyc$ \.pyc$
\.pylintrc$
\.qm$
\.s$ \.s$
\.stl$ \.sig$
\.svg$ \.so$
\.svgz?$ \.svgz?$
\.sys$
\.tar$ \.tar$
\.tgz$
\.tiff?$ \.tiff?$
\.ttf$ \.ttf$
\.wav$ \.wav$
\.webm$ \.webm$
\.webp$ \.webp$
\.woff2?$ \.woff2?$
\.xcf$
\.xlsx?$ \.xlsx?$
\.xpm$
\.xz$
\.zip$ \.zip$
^\.github/actions/spell-check/ ^\.github/actions/spell-check/
^\.gitmodules$ ^\.gitmodules$
@ -79,38 +98,28 @@
^\Q.pipelines/ESRPSigning_core.json\E$ ^\Q.pipelines/ESRPSigning_core.json\E$
^\Qinstaller/PowerToysSetup/Settings.wxs\E$ ^\Qinstaller/PowerToysSetup/Settings.wxs\E$
^\Qsrc/common/ManagedCommon/ColorFormatHelper.cs\E$ ^\Qsrc/common/ManagedCommon/ColorFormatHelper.cs\E$
^\Q.pipelines/sdl.gdnbaselines\E$
^\Qsrc/common/FilePreviewCommon/Assets/Monaco/monaco_languages.json\E$
^\Qsrc/common/notifications/BackgroundActivatorDLL/cpp.hint\E$
^\Qsrc/modules/colorPicker/ColorPickerUI/Assets/ColorPicker/colorPicker.cur\E$
^\Qsrc/modules/colorPicker/ColorPickerUI/Shaders/GridShader.cso\E$ ^\Qsrc/modules/colorPicker/ColorPickerUI/Shaders/GridShader.cso\E$
^\Qsrc/modules/MouseUtils/MouseJumpUI/MainForm.resx\E$ ^\Qsrc/modules/MouseUtils/MouseJumpUI/MainForm.resx\E$
^\Qsrc/modules/MouseWithoutBorders/App/Form/frmAbout.cs\E$ ^\Qsrc/modules/MouseWithoutBorders/App/Form/frmAbout.cs\E$
^\Qsrc/modules/MouseWithoutBorders/App/Properties/AssemblyInfo.cs\E$
^\Qsrc/modules/MouseWithoutBorders/ModuleInterface/generateSecurityDescriptor.h\E$ ^\Qsrc/modules/MouseWithoutBorders/ModuleInterface/generateSecurityDescriptor.h\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/CorruptJson/Microsoft/PowerToys/settings.json\E$ ^\Qsrc/modules/MouseUtils/MouseJumpUI/NativeMethods/User32/UI/WindowsAndMessaging/User32.SYSTEM_METRICS_INDEX.cs\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/v0.18.2/Microsoft/PowerToys/PowerRename/power-rename-ui-flags\E$ ^\Qsrc/modules/MouseWithoutBorders/App/Form/frmInputCallback.resx\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/v0.19.2/Microsoft/PowerToys/PowerRename/power-rename-ui-flags\E$ ^\Qsrc/modules/MouseWithoutBorders/App/Form/frmLogon.resx\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/v0.20.1/Microsoft/PowerToys/PowerRename/power-rename-ui-flags\E$ ^\Qsrc/modules/MouseWithoutBorders/App/Form/frmMatrix.resx\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/V0.21.1/Microsoft/PowerToys/FancyZones/settings.json\E$ ^\Qsrc/modules/MouseWithoutBorders/App/Form/frmScreen.resx\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/V0.21.1/Microsoft/PowerToys/PowerRename/power-rename-ui-flags\E$ ^\Qsrc/modules/peek/Peek.Common/NativeMethods.txt\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/v0.22.0/Microsoft/PowerToys/FancyZones/settings.json\E$ ^\Qsrc/modules/previewpane/SvgPreviewHandler/SvgHTMLPreviewGenerator.cs\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/v0.22.0/Microsoft/PowerToys/PowerRename/power-rename-ui-flags\E$ ^\Qsrc/modules/previewpane/UnitTests-StlThumbnailProvider/HelperFiles/sample.stl\E$
^\Qtools/project_template/ModuleTemplate/resource.h\E$ ^\Qtools/project_template/ModuleTemplate/resource.h\E$
^doc/devdocs/akaLinks\.md$ ^doc/devdocs/akaLinks\.md$
^installer/PowerToysSetup/WebView2/MicrosoftEdgeWebview2Setup.exe$
^src/common/logger/logger\.vcxproj\.filters$
^src/common/notifications/BackgroundActivatorDLL/BackgroundActivator\.vcxproj\.filters$
^src/common/notifications/BackgroundActivatorDLL/cpp\.hint$
^src/modules/colorPicker/ColorPickerUI/Assets/ColorPicker/colorPicker\.cur$
^src/modules/fancyzones/lib/FancyZonesWinHookEventIDs\.h$
^src/modules/imageresizer/dll/ContextMenuHandler\.rgs$
^src/modules/imageresizer/dll/ImageResizerExt\.rgs$
^src/modules/MouseUtils/MouseJumpUI/NativeMethods/User32/UI/WindowsAndMessaging/User32.SYSTEM_METRICS_INDEX.cs$
^src/modules/MouseWithoutBorders/App/Form/.*\.resx$ ^src/modules/MouseWithoutBorders/App/Form/.*\.resx$
^src/modules/MouseWithoutBorders/App/Form/.*\.Designer\.cs$ ^src/modules/MouseWithoutBorders/App/Form/.*\.Designer\.cs$
^src/modules/MouseWithoutBorders/App/Helper/.*\.resx$ ^src/modules/MouseWithoutBorders/App/Helper/.*\.resx$
^src/modules/MouseWithoutBorders/App/.*/NativeMethods\.cs$ ^src/modules/MouseWithoutBorders/App/.*/NativeMethods\.cs$
^src/modules/peek/Peek\.Common/NativeMethods\.txt$
^src/modules/powerrename/testapp/PowerRenameTest\.vcxproj\.filters$
^src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithHTMLImageTag\.txt$
^src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithHTMLImageTag.txt$ ^src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithHTMLImageTag.txt$
^tools/CleanUp_tool/CleanUp_tool\.vcxproj\.filters$
^tools/Verification scripts/Check preview handler registration\.ps1$ ^tools/Verification scripts/Check preview handler registration\.ps1$
ignore$ ignore$

View File

@ -21,6 +21,7 @@ activationaction
ADDUNDORECORD ADDUNDORECORD
ADifferent ADifferent
adio adio
adipiscing
administra administra
ADMINS ADMINS
adml adml
@ -34,6 +35,7 @@ AGGREGATABLE
AHybrid AHybrid
ALarger ALarger
alekhyareddy alekhyareddy
aliquip
ALLAPPS ALLAPPS
ALLINPUT ALLINPUT
ALLOWUNDO ALLOWUNDO
@ -97,6 +99,7 @@ ASingle
ASSOCCHANGED ASSOCCHANGED
ASYNCWINDOWPLACEMENT ASYNCWINDOWPLACEMENT
ASYNCWINDOWPOS ASYNCWINDOWPOS
ative
atl atl
atlbase atlbase
atlcom atlcom
@ -150,7 +153,6 @@ BLURREGION
bmi bmi
bms bms
BNumber BNumber
Bokm
BOKMAL BOKMAL
bootstrapper bootstrapper
BOOTSTRAPPERINSTALLFOLDER BOOTSTRAPPERINSTALLFOLDER
@ -172,6 +174,7 @@ BTNFACE
Bto Bto
buf buf
bugreport bugreport
BUILDARCH
BUILDNUMBER BUILDNUMBER
buildtask buildtask
buildtransitive buildtransitive
@ -274,6 +277,7 @@ cominterop
commandline commandline
COMMANDTITLE COMMANDTITLE
commctrl commctrl
commodo
compmgmt compmgmt
COMPOSITIONFULL COMPOSITIONFULL
comsupp comsupp
@ -284,6 +288,8 @@ CONFIGW
CONFLICTINGMODIFIERKEY CONFLICTINGMODIFIERKEY
CONFLICTINGMODIFIERSHORTCUT CONFLICTINGMODIFIERSHORTCUT
CONOUT CONOUT
consectetur
consequat
Consolas Consolas
constexpr constexpr
consts consts
@ -326,6 +332,7 @@ CTRLALTDEL
Ctrls Ctrls
Ctx Ctx
CUI CUI
cupidatat
currentculture currentculture
CURRENTDIR CURRENTDIR
CURSORINFO CURSORINFO
@ -372,6 +379,7 @@ dcomp
DComposition DComposition
dcr dcr
dcs dcs
ddd
DDEIf DDEIf
DDevice DDevice
ddf ddf
@ -398,12 +406,12 @@ DELETEDKEYIMAGE
DELETESCANS DELETESCANS
deletethis deletethis
Delimarsky Delimarsky
dend
DENORMAL DENORMAL
Deondre Deondre
depersist depersist
deprioritized deprioritized
deref deref
deserunt
DESKTOPABSOLUTEEDITING DESKTOPABSOLUTEEDITING
DESKTOPABSOLUTEPARSING DESKTOPABSOLUTEPARSING
desktopshorcutinstalled desktopshorcutinstalled
@ -484,6 +492,7 @@ dxgidebug
dxgiformat dxgiformat
dxguid dxguid
ecount ecount
ecyclebin
EData EData
Edid Edid
EDITKEYBOARD EDITKEYBOARD
@ -491,8 +500,13 @@ editkeyboardwindow
EDITSHORTCUTS EDITSHORTCUTS
editshortcutswindow editshortcutswindow
EFile EFile
egistry
egistrypreview
eip eip
ekus ekus
elease
elemetry
elit
emmintrin emmintrin
Emoji Emoji
ENABLEDELAYEDEXPANSION ENABLEDELAYEDEXPANSION
@ -503,6 +517,7 @@ encryptor
endpointvolume endpointvolume
endregion endregion
ENDSESSION ENDSESSION
enim
ENTERSIZEMOVE ENTERSIZEMOVE
ENU ENU
EOAC EOAC
@ -517,10 +532,16 @@ ERRORLEVEL
ERRORTITLE ERRORTITLE
ESettings ESettings
esize esize
esource
esrp esrp
estapp
estart
ests
esult
etl etl
etstat etstat
etw ETW
etwork
EUQ EUQ
eurochange eurochange
eventlog eventlog
@ -538,6 +559,7 @@ exabyte
examplehandler examplehandler
examplepowertoy examplepowertoy
EXAND EXAND
Excepteur
EXCLUDEFROMCAPTURE EXCLUDEFROMCAPTURE
exdisp exdisp
executionpolicy executionpolicy
@ -548,6 +570,8 @@ exlist
EXPCMDFLAGS EXPCMDFLAGS
EXPCMDSTATE EXPCMDSTATE
explr explr
exppowertoys
exptas
exsb exsb
EXSEL EXSEL
exstyle exstyle
@ -575,7 +599,7 @@ FILEOP
FILEOS FILEOS
FILESUBTYPE FILESUBTYPE
FILESYSPATH FILESYSPATH
filetime Filetime
FILEVERSION FILEVERSION
Filtergraph Filtergraph
Filterkeyboard Filterkeyboard
@ -585,6 +609,7 @@ findfast
firefox firefox
FIXEDFILEINFO FIXEDFILEINFO
flyout flyout
flyouts
FOF FOF
FOFX FOFX
FOLDERID FOLDERID
@ -907,6 +932,8 @@ killrunner
Knownfolders Knownfolders
KSPROPERTY KSPROPERTY
Kybd Kybd
laboris
laborum
LAlt LAlt
Lambson Lambson
langword langword
@ -957,6 +984,7 @@ lmcons
LMEM LMEM
LMENU LMENU
lnk lnk
lnks
LOADFROMFILE LOADFROMFILE
LOBYTE LOBYTE
LOCALAPPDATA LOCALAPPDATA
@ -1028,6 +1056,7 @@ majortype
MAJORVERSION MAJORVERSION
makecab makecab
MAKEINTRESOURCE MAKEINTRESOURCE
MAKEINTRESOURCEA
MAKEINTRESOURCEW MAKEINTRESOURCEW
makepri makepri
manifestdependency manifestdependency
@ -1110,6 +1139,7 @@ mockapi
MODECHANGE MODECHANGE
modernwpf modernwpf
MODESPRUNED MODESPRUNED
mollit
MONITORENUMPROC MONITORENUMPROC
MONITORINFO MONITORINFO
MONITORINFOEX MONITORINFOEX
@ -1154,10 +1184,12 @@ msrc
msstore msstore
mst mst
msvc msvc
msvcp
MTND MTND
Mul Mul
MULTIPLEUSE MULTIPLEUSE
multizone multizone
muxc
mvvm mvvm
mwb mwb
MWBEx MWBEx
@ -1182,6 +1214,7 @@ NCMBUTTONUP
NCMOUSELEAVE NCMOUSELEAVE
NCMOUSEMOVE NCMOUSEMOVE
NCol NCol
nconsectetur
ncpa ncpa
NCPAINT NCPAINT
NCRBUTTONDBLCLK NCRBUTTONDBLCLK
@ -1206,7 +1239,6 @@ newitem
newpath newpath
newrow newrow
Newtonsoft Newtonsoft
niels
nielslaute nielslaute
NIF NIF
nint nint
@ -1223,6 +1255,8 @@ NOCOPYBITS
nodeca nodeca
nodiscard nodiscard
nodoc nodoc
NODRAWCAPTION
NODRAWICON
NOINHERITLAYOUT NOINHERITLAYOUT
NOINTERFACE NOINTERFACE
NOLINKINFO NOLINKINFO
@ -1249,6 +1283,7 @@ NORMALUSER
NOSEARCH NOSEARCH
NOSENDCHANGING NOSENDCHANGING
NOSIZE NOSIZE
nostrud
notfound notfound
NOTIFICATIONSDLL NOTIFICATIONSDLL
NOTIFYICONDATAW NOTIFYICONDATAW
@ -1264,6 +1299,7 @@ NOZORDER
NPH NPH
NResize NResize
nrw nrw
nsunt
NTAPI NTAPI
ntdll ntdll
ntfs ntfs
@ -1280,12 +1316,15 @@ Objbase
OBJID OBJID
objidl objidl
oblitum oblitum
obmikh
occaecat
ocr ocr
Ocrsettings Ocrsettings
odbc odbc
odbccp odbccp
Oem Oem
officehubintl officehubintl
officia
ofs ofs
oid oid
oldcolor oldcolor
@ -1302,6 +1341,7 @@ onenote
onstd onstd
oobe oobe
OOBEPT OOBEPT
ools
opencode opencode
opensource opensource
openxmlformats openxmlformats
@ -1315,6 +1355,8 @@ ostr
OSVERSIONINFOEX OSVERSIONINFOEX
OSVERSIONINFOEXW OSVERSIONINFOEXW
osvi osvi
otating
otifications
OUTOFCONTEXT OUTOFCONTEXT
OUTOFMEMORY OUTOFMEMORY
outpin outpin
@ -1461,6 +1503,7 @@ PRODUCTVERSION
Progman Progman
programdata programdata
PROGRAMFILES PROGRAMFILES
proident
projectname projectname
PROPBAG PROPBAG
PROPERTYKEY PROPERTYKEY
@ -1541,6 +1584,7 @@ RECTL
rectp rectp
rects rects
RECTSOURCE RECTSOURCE
recyclebin
redirectedfrom redirectedfrom
Redist Redist
redistributable redistributable
@ -1579,6 +1623,7 @@ renamable
RENAMEONCOLLISION RENAMEONCOLLISION
Renamer Renamer
reparent reparent
reparented
reparenting reparenting
reparse reparse
reportbug reportbug
@ -1612,6 +1657,7 @@ RIGHTDOWN
RIGHTSCROLLBAR RIGHTSCROLLBAR
RIGHTUP RIGHTUP
riid riid
ringbuffer
RKey RKey
RLO RLO
RMENU RMENU
@ -1671,13 +1717,13 @@ Scode
scoobe scoobe
SCOPEID SCOPEID
screenshot screenshot
screenshots
scrollviewer scrollviewer
sddl sddl
SDKDDK SDKDDK
sdns sdns
searchterm searchterm
secpol secpol
Secur
Segoe Segoe
Sekan Sekan
SENDCHANGE SENDCHANGE
@ -1753,6 +1799,7 @@ sia
SIATTRIBFLAGS SIATTRIBFLAGS
SICHINT SICHINT
sid sid
SIDs
siex siex
sigdn sigdn
SIGNINGSCENARIO SIGNINGSCENARIO
@ -1853,6 +1900,7 @@ stylecop
Subdir Subdir
subfolders subfolders
subkey subkey
subkeys
SUBLANG SUBLANG
subquery subquery
subresource subresource
@ -1888,7 +1936,7 @@ SYSTEMTIME
sysvol sysvol
Tadele Tadele
talynone talynone
TApp tapp
TApplication TApplication
TApplied TApplied
targ targ
@ -1966,6 +2014,7 @@ Tsd
TServer TServer
TStr TStr
TValue TValue
tweakme
TWF TWF
tymed tymed
typedef typedef
@ -1988,6 +2037,7 @@ UIEx
uipi uipi
UIs UIs
ULARGE ULARGE
ullamco
ULONGLONG ULONGLONG
ums ums
unapply unapply
@ -2009,6 +2059,7 @@ unknwn
UNLEN UNLEN
Unmap Unmap
unmute unmute
unner
UNORM UNORM
unregistering unregistering
unremapped unremapped
@ -2049,6 +2100,7 @@ VCINSTALLDIR
vcm vcm
Vcpkg Vcpkg
VCRT VCRT
vcruntime
vcvars vcvars
VDesktop VDesktop
vdi vdi
@ -2117,6 +2169,7 @@ webpage
websearch websearch
webserver webserver
website website
websites
wekyb wekyb
Wevtapi Wevtapi
wgpocpl wgpocpl
@ -2187,7 +2240,7 @@ WKSG
Wlkr Wlkr
wmain wmain
Wman Wman
wmi WMI
WMICIM WMICIM
wmimgmt wmimgmt
WMKEYDOWN WMKEYDOWN
@ -2230,6 +2283,8 @@ wsl
wss wss
wstr wstr
wsz wsz
WTA
WTNCA
wtoi wtoi
WTS WTS
wtsapi wtsapi

View File

@ -1,4 +1,6 @@
# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere # reject `m_data` as VxWorks defined it and that breaks things if it's used elsewhere
# see [fprime](https://github.com/nasa/fprime/commit/d589f0a25c59ea9a800d851ea84c2f5df02fb529)
# and [Qt](https://github.com/qtproject/qt-solutions/blame/fb7bc42bfcc578ff3fa3b9ca21a41e96eb37c1c7/qtscriptclassic/src/qscriptbuffer_p.h#L46)
# \bm_data\b # \bm_data\b
# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test, # If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test,
@ -6,40 +8,72 @@
# to use this: # to use this:
#\bfit\( #\bfit\(
# s.b. anymore
\bany more[,.]
# s.b. GitHub # s.b. GitHub
\bGithub\b (?<![&*.]|// |\btype )\bGithub\b(?![{)])
# s.b. GitLab # s.b. GitLab
\bGitlab\b (?<![&*.]|// |\btype )\bGitlab\b(?![{)])
# s.b. JavaScript # s.b. JavaScript
\bJavascript\b \bJavascript\b
# s.b. macOS or Mac OS X or ...
\bMacOS\b
# s.b. Microsoft # s.b. Microsoft
\bMicroSoft\b \bMicroSoft\b
# s.b. TypeScript
\bTypescript\b
# s.b. another # s.b. another
\ban[- ]other\b \ban[- ]other\b
# s.b. deprecation warning
\b[Dd]epreciation [Ww]arnings?\b
# s.b. greater than # s.b. greater than
\bgreater then\b \bgreater then\b
# s.b. in front of
\bin from of\b
# s.b. into # s.b. into
\sin to\s # when not phrasal and when `in order to` would be wrong:
# https://thewritepractice.com/into-vs-in-to/
\sin to\s(?!if\b)
# s.b. is obsolete
\bis obsolescent\b
# s.b. it's or its
\bits[']
# s.b. opt-in # s.b. opt-in
\sopt in\s (?<!\sfor)\sopt in\s
# s.b. less than # s.b. less than
\bless then\b \bless then\b
# s.b. one of
\bon of\b
# s.b. otherwise # s.b. otherwise
\bother[- ]wise\b \bother[- ]wise\b
# s.b. or (more|less)
\bore (?:more|less)\b
# s.b. nonexistent # s.b. nonexistent
\bnon existing\b \bnon existing\b
\b[Nn]o[nt][- ]existent\b \b[Nn]o[nt][- ]existent\b
# s.b. brief / details/ param / return / retval
(?:^\s*|(?:\*|//|/*)\s+`)[\\@](?:breif|(?:detail|detials)|(?:params(?!\.)|prama?)|ret(?:uns?)|retvl)\b
# s.b. preexisting # s.b. preexisting
[Pp]re[- ]existing [Pp]re[- ]existing
@ -49,14 +83,37 @@
# s.b. preemptively # s.b. preemptively
[Pp]re[- ]emptively [Pp]re[- ]emptively
# s.b. recently changed or recent changes
[Rr]ecent changed
# s.b. reentrancy # s.b. reentrancy
[Rr]e[- ]entrancy [Rr]e[- ]entrancy
# s.b. reentrant # s.b. reentrant
[Rr]e[- ]entrant [Rr]e[- ]entrant
# s.b. workaround(s) # s.b. understand
#\bwork[- ]arounds?\b \bunder stand\b
# Reject duplicate words # s.b. workarounds
#\bwork[- ]arounds\b
# s.b. workaround
(?:(?:[Aa]|[Tt]he|ugly)\swork[- ]around\b|\swork[- ]around\s+for)
# s.b. (coarse|fine)-grained
\b(?:coarse|fine) grained\b
# s.b. neither/nor -- or reword
#\bnot\b[^.?!"/(]+\bnor\b
# probably a double negative
# s.b. neither/nor (plus rewording the beginning)
\bnot\b[^.?!"/]*\bneither\b[^.?!"/(]*\bnor\b
# In English, it is generally wrong to have the same word twice in a row without punctuation.
# Duplicated words are generally mistakes.
# There are a few exceptions where it is acceptable (e.g. "that that").
# If the highlighted doubled word pair is in a code snippet, you can write a pattern to mask it.
# If the highlighted doubled word pair is in prose, have someone read the English before you dismiss this error.
\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s \s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s

View File

@ -1,179 +1,177 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns # See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
# Automatically suggested patterns # Automatically suggested patterns
# hit-count: 2206 file-count: 617 # hit-count: 3011 file-count: 842
# IServiceProvider # IServiceProvider / isAThing
\bI(?=(?:[A-Z][a-z]{2,})+\b) \b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b)
# hit-count: 111 file-count: 57 # hit-count: 2239 file-count: 134
# hex runs # hex runs
\b[0-9a-fA-F]{16,}\b \b[0-9a-fA-F]{16,}\b
# hit-count: 89 file-count: 36 # hit-count: 1868 file-count: 1
# sha-... -- uses a fancy capture
(\\?['"]|&quot;)[0-9a-f]{40,}\g{-1}
# hit-count: 1100 file-count: 97
# base64 encoded content, possibly wrapped in mime
(?:^|[\s=;:?])[-a-zA-Z=;:/0-9+]{50,}(?:[\s=;:?]|$)
# hit-count: 426 file-count: 165
# GitHub SHAs (markdown) # GitHub SHAs (markdown)
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|) (?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
# hit-count: 67 file-count: 59 # hit-count: 331 file-count: 117
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
# hit-count: 275 file-count: 45
# version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# hit-count: 209 file-count: 97
# w3 # w3
\bw3\.org/[-0-9a-zA-Z/#.]+ \bw3\.org/[-0-9a-zA-Z/#.]+
# hit-count: 47 file-count: 3 # hit-count: 137 file-count: 38
# alternate markers if you run into latex and friends
(?<!\\)\\[nrt](?=[a-z]{2,})(?=.*['"`](?:, "[^{]|\]))
# tabs in c#
\$"\\t
# windows line breaks in strings
\\r\\n
# hit-count: 104 file-count: 43
# regex choice
\(\?:[^)]+\|[^)]+\)
# hit-count: 76 file-count: 28
# base64 encoded content
([`'"])[-a-zA-Z=;:/0-9+]+=\g{-1}
# hit-count: 70 file-count: 5
# Contributor # Contributor
\[[^\]]+\]\(https://github\.com/[^/\s"]+\) \[[^\]]+\]\(https://github\.com/[^/\s"]+/?\)
# hit-count: 45 file-count: 2 # hit-count: 28 file-count: 22
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
# hit-count: 22 file-count: 18
# stackexchange -- https://stackexchange.com/feeds/sites # stackexchange -- https://stackexchange.com/feeds/sites
\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/) \b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/)
# hit-count: 7 file-count: 3 # hit-count: 21 file-count: 2
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
## Operation "substitution (s///)" returns its argument for non-Unicode code point 0x1C19AE (the code point will vary).
## You could manually change `(?i)X...` to use `[Xx]...`
## or you could add the files to your `excludes` file (a version after 0.0.19 should identify the file path)
# Lorem
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
# hit-count: 18 file-count: 15
# microsoft
\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]*
# hit-count: 14 file-count: 5
# githubusercontent
/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
# hit-count: 14 file-count: 3
# node packages
(["'])\@[^/'" ]+/[^/'" ]+\g{-1}
# hit-count: 10 file-count: 4
# URL escaped characters
\%[0-9A-F][A-F]
# hit-count: 9 file-count: 5
# Wikipedia # Wikipedia
\ben\.wikipedia\.org/wiki/[-\w%.#]+ \ben\.wikipedia\.org/wiki/[-\w%.#]+
# hit-count: 6 file-count: 3
# css url wrappings
\burl\([^)]+\)
# hit-count: 5 file-count: 3 # hit-count: 5 file-count: 3
# vs devops # vs devops
\bvisualstudio.com(?::443|)/[-\w/?=%&.]* \bvisualstudio.com(?::443|)/[-\w/?=%&.]*
# hit-count: 3 file-count: 3 # hit-count: 4 file-count: 3
# githubusercontent # Non-English
/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]* [a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
# hit-count: 4 file-count: 2
# data url in quotes
([`'"])data:(?:[^ `'"].*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
# hit-count: 2 file-count: 2 # hit-count: 2 file-count: 2
# mailto urls # mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,} mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
https?://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
# GitHub SHAs
\bapi.github\.com/repos/[^/]+/[^/]+/[^/]+/[0-9a-f]+\b
://github\.(?:com|blog)/[^\w")]+
(?:\[[0-9a-f]+\]\(https:/|)/github\.com/[^/]+/[^/]+/[^/]+/[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b
# githubusercontent
://githubusercontent\.com/[^\w")]+
# gist github
/gist\.github\.com/[^/]+/[0-9a-f]+
# msdn # msdn
\b(?:download\.visualstudio|docs|msdn|learn)\.microsoft\.com/[-_a-zA-Z0-9()=./]* \b(?:download\.visualstudio|docs|msdn|learn)\.microsoft\.com/[-_a-zA-Z0-9()=./]*
aka\.ms/[a-zA-Z0-9]+ aka\.ms/[a-zA-Z0-9]+
# medium # hit-count: 2 file-count: 1
link\.medium\.com/[a-zA-Z0-9]+ # While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
\bmedium\.com/\@[^/]+/[-\w]+ # YouTube url
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
# experimentation urls
https?://default\.exp-tas\.com/[-_a-zA-Z0-9/]*
publicKeyToken=(['"]|)[0-9a-f]+\g{-1}
\@sha256:[0-9a-f]{64}\b
# data urls
(['"])data:.*?\g{-1}
data:[-a-zA-Z=;:/0-9+]*,\S*
# uuid: (or CompGUIDPrefix) # uuid: (or CompGUIDPrefix)
L?(["']|[-<({>]|\b)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{10,12}(?:\g{-1}|[<})>]) L?(["']|[-<({>]|\b)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{10,12}(?:\g{-1}|[<})>])
# c99 hex digits (not the full format, just one I've seen)
0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP]
# URL escaped characters
\%[0-9A-F]{2}
# wregex
std::wregex\(L"[^"]*"\)
# hash
Hash="[0-9A-F]{40}"
# SHA256 hash
'[0-9A-F]{64}'
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23|L")[0-9a-fA-FgGrR_]{2,}(?:[uU]?[lL]{0,2}|u\d+)\b
(?:L"[abAB]+", ){3}L"[abAB]+" (?:L"[abAB]+", ){3}L"[abAB]+"
"Lorem[^"]+?\."
TestCase\("[^"]+"
# Test line with hexadecimal colors # hit-count: 1 file-count: 1
\[DataRow\("[0-9A-F]{6}", \d{3}, \d{3}, \d{3}\)\] # marker to ignore all code on line
\[DataRow\("[0-9A-F]{6}", \d{3}.\d{1}, \d{3}.\d{1}, \d{3}.\d{1}\)\] ^.*/\* #no-spell-check-line \*/.*$
\[DataRow\("[0-9A-F]{6}", "[BCGMRY]\d\d?", \d{3}, \d{3}\)\]
# version suffix <word>v#
[Vv]\d+(?:\b|(?=[a-zA-Z_]))
# Windows paths
\\native
\\netcoreapp
\\netstandard
\\network
\\notifications
\\recyclebin
\\Registry
\\registry
\\reinstall
\\release
\\Resize
\\resource
\\Resources
\\restart
\\restore
\\result
\\robmikh
\\rotating
\\runner
\\runtimes
\\Telemetry
\\telemetry
\\testapp
\\tests
\\tools
# plugin.json
^ "ID": "[0-9A-F]{32}",$
# UnitTests # UnitTests
\[DataRow\(.*\)\] \[DataRow\(.*\)\]
# Id info inside markdown file (registry.md)
^\|\s+ID\s+\|\s*\`[0-9A-F]{32}\`
# TestCase strings intentionally have non dictionary items
\[TestCase\(new string.*\]
# D2D # D2D
D?2D D?2D
# marker for ignoring a comment to the end of the line # hit-count: 1 file-count: 1
^.*/\* #no-spell-check-line \*/.*$ # GHSA
// #no-spell-check.*$ GHSA(?:-[0-9a-z]{4}){3}
http://tes/ # hit-count: 1 file-count: 1
# medium
\bmedium\.com/\@?[^/\s"]+/[-\w]+
# hit-count: 1 file-count: 1
# kubectl.kubernetes.io/last-applied-configuration
"kubectl.kubernetes.io/last-applied-configuration": ".*"
# hit-count: 1 file-count: 1
# tar arguments # tar arguments
\b(?:\\n|)tar(?:\s+-[a-zA-Z]+|\s[a-z]+)+ \b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
\bSecur32
# fabricbot.json
"id": "\S+"
"commentPattern": ".*"
# Questionably acceptable forms of `in to` # Questionably acceptable forms of `in to`
# Personally, I prefer `log into`, but people object # Personally, I prefer `log into`, but people object
# https://www.tprteaching.com/log-into-log-in-to-login/ # https://www.tprteaching.com/log-into-log-in-to-login/
\b[Ll]og in to\b \b(?:[Ll]og|[Ss]ign) in to\b
# to opt in
\bto opt in\b
# acceptable duplicates # acceptable duplicates
# ls directory listings # ls directory listings
# /bin/ls -l output [-bcdlpsw](?:[-r][-w][-Ssx]){3}\s+\d+\s+\S+\s+\S+\s+\d+\s+
[-bcdlpsw](?:[-r][-w][-sx]){3}\s+\d+\s+(\S+)\s+\g{-1}\s+\d+\s+ # mount
\bmount\s+-t\s+(\w+)\s+\g{-1}\b
# C types and repeated CSS values # C types and repeated CSS values
\s(center|div|inherit|long|LONG|none|normal|solid|thin|transparent|very)(?: \g{-1})+\s \s(auto|center|div|inherit|long|LONG|none|normal|solid|thin|transparent|very)(?: \g{-1})+\s
# C struct
\bstruct\s+(\w+)\s+\g{-1}\b
# go templates # go templates
\s(\w+)\s+\g{-1}\s+\`(?:graphql|json|yaml): \s(\w+)\s+\g{-1}\s+\`(?:graphql|inject|json|yaml):
# javadoc / .net # doxygen / javadoc / .net
(?:[\\@](?:groupname|param)|(?:public|private)(?:\s+static|\s+readonly)*)\s+(\w+)\s+\g{-1}\s (?:[\\@](?:brief|groupname|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+static|\s+override|\s+readonly)*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s
# Commit message -- Signed-off-by and friends # Commit message -- Signed-off-by and friends
^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$ ^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$

View File

@ -1,4 +1,5 @@
^attache$ ^attache$
^bellow$
benefitting benefitting
occurences? occurences?
^dependan.* ^dependan.*

View File

@ -5,7 +5,7 @@ name: Spell checking
# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions # https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions
# #
# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment # `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment
# (in odd cases, it might actually run just to collapse a commment, but that's fairly rare) # (in odd cases, it might actually run just to collapse a comment, but that's fairly rare)
# it needs `contents: write` in order to add a comment. # it needs `contents: write` in order to add a comment.
# #
# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment # `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment
@ -34,6 +34,29 @@ name: Spell checking
# #
# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key # For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key
# Sarif reporting
#
# Access to Sarif reports is generally restricted (by GitHub) to members of the repository.
#
# Requires enabling `security-events: write`
# and configuring the action with `use_sarif: 1`
#
# For information on the feature, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Sarif-output
# Minimal workflow structure:
#
# on:
# push:
# ...
# pull_request_target:
# ...
# jobs:
# # you only want the spelling job, all others should be omitted
# spelling:
# # remove `security-events: write` and `use_sarif: 1`
# # remove `experimental_apply_changes_via_bot: 1`
# ... otherwise adjust the `with:` as you wish
on: on:
push: push:
branches: branches:
@ -43,12 +66,13 @@ on:
pull_request_target: pull_request_target:
branches: branches:
- "**" - "**"
tags-ignore:
- "**"
types: types:
- 'opened' - 'opened'
- 'reopened' - 'reopened'
- 'synchronize' - 'synchronize'
issue_comment:
types:
- 'created'
jobs: jobs:
spelling: spelling:
@ -57,10 +81,11 @@ jobs:
contents: read contents: read
pull-requests: read pull-requests: read
actions: read actions: read
security-events: write
outputs: outputs:
followup: ${{ steps.spelling.outputs.followup }} followup: ${{ steps.spelling.outputs.followup }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: "contains(github.event_name, 'pull_request') || github.event_name == 'push'" if: ${{ contains(github.event_name, 'pull_request') || github.event_name == 'push' }}
concurrency: concurrency:
group: spelling-${{ github.event.pull_request.number || github.ref }} group: spelling-${{ github.event.pull_request.number || github.ref }}
# note: If you use only_check_changed_files, you do not want cancel-in-progress # note: If you use only_check_changed_files, you do not want cancel-in-progress
@ -68,24 +93,45 @@ jobs:
steps: steps:
- name: check-spelling - name: check-spelling
id: spelling id: spelling
uses: check-spelling/check-spelling@v0.0.21 uses: check-spelling/check-spelling@v0.0.22
with: with:
config: .github/actions/spell-check config: .github/actions/spell-check
suppress_push_for_open_pull_request: 1 suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
checkout: true checkout: true
check_file_names: 1 check_file_names: 1
spell_check_this: check-spelling/spell-check-this@prerelease spell_check_this: microsoft/PowerToys@main
post_comment: 0 post_comment: 0
use_magic_file: 1 use_magic_file: 1
extra_dictionary_limit: 10 warnings: bad-regex,binary-file,deprecated-feature,ignored-expect-variant,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }}
extra_dictionary_limit: 20
extra_dictionaries: extra_dictionaries:
cspell:software-terms/src/software-terms.txt cspell:software-terms/dict/softwareTerms.txt
cspell:cpp/src/stdlib-cpp.txt cspell:cpp/src/stdlib-cpp.txt
cspell:filetypes/filetypes.txt cspell:filetypes/filetypes.txt
cspell:cpp/src/stdlib-c.txt cspell:cpp/src/stdlib-c.txt
cspell:fullstack/fullstack.txt cspell:python/src/python/python-lib.txt
cspell:html/html.txt cspell:lorem-ipsum/dictionary.txt
cspell:css/css.txt cspell:php/dict/php.txt
cspell:typescript/dict/typescript.txt
cspell:swift/src/swift.txt
cspell:fullstack/dict/fullstack.txt
cspell:node/dict/node.txt
cspell:dotnet/dict/dotnet.txt
cspell:django/dict/django.txt
cspell:python/src/python/python.txt
cspell:csharp/csharp.txt
cspell:python/src/common/extra.txt
cspell:cpp/src/compiler-msvc.txt
cspell:aws/aws.txt
cspell:golang/dict/go.txt
cspell:java/src/java.txt
cspell:html/dict/html.txt
cspell:css/dict/css.txt
cspell:k8s/dict/k8s.txt
cspell:java/src/java-terms.txt
cspell:powershell/dict/powershell.txt
comment-push: comment-push:
name: Report (Push) name: Report (Push)
@ -97,11 +143,11 @@ jobs:
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push' if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
steps: steps:
- name: comment - name: comment
uses: check-spelling/check-spelling@v0.0.21 uses: check-spelling/check-spelling@v0.0.22
with: with:
config: .github/actions/spell-check config: .github/actions/spell-check
checkout: true checkout: true
spell_check_this: check-spelling/spell-check-this@prerelease spell_check_this: microsoft/PowerToys@main
task: ${{ needs.spelling.outputs.followup }} task: ${{ needs.spelling.outputs.followup }}
comment-pr: comment-pr:
@ -110,13 +156,39 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: spelling needs: spelling
permissions: permissions:
contents: read
pull-requests: write pull-requests: write
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request') if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
steps: steps:
- name: comment - name: comment
uses: check-spelling/check-spelling@v0.0.21 uses: check-spelling/check-spelling@v0.0.22
with: with:
config: .github/actions/spell-check config: .github/actions/spell-check
checkout: true checkout: true
spell_check_this: check-spelling/spell-check-this@prerelease spell_check_this: check-spelling/spell-check-this@prerelease
task: ${{ needs.spelling.outputs.followup }} task: ${{ needs.spelling.outputs.followup }}
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
update:
name: Update PR
permissions:
contents: write
pull-requests: write
actions: read
runs-on: ubuntu-latest
if: ${{
github.repository_owner != 'microsoft' &&
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, '@check-spelling-bot apply')
}}
concurrency:
group: spelling-update-${{ github.event.issue.number }}
cancel-in-progress: false
steps:
- name: apply spelling updates
uses: check-spelling/check-spelling@v0.0.22
with:
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
checkout: true
ssh_key: "${{ secrets.CHECK_SPELLING }}"

View File

@ -25,7 +25,11 @@ $nullVersionExceptions = @(
"codicon.ttf", "codicon.ttf",
"e_sqlite3.dll", "e_sqlite3.dll",
"vcamp140_app.dll", "vcamp140_app.dll",
"vcruntime140_app.dll",
"vcruntime140_1_app.dll",
"msvcp140_app.dll",
"marshal.dll", "marshal.dll",
"Microsoft.Toolkit.Win32.UI.XamlHost.dll",
"Microsoft.UI.Composition.OSSupport.dll", "Microsoft.UI.Composition.OSSupport.dll",
"Microsoft.UI.Windowing.dll", "Microsoft.UI.Windowing.dll",
"Microsoft.UI.Xaml.Internal.dll", "Microsoft.UI.Xaml.Internal.dll",

View File

@ -34,7 +34,7 @@
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0-rc.2.23479.6" /> <PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0-rc.2.23479.6" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.3" /> <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" /> <PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.1722.45" /> <PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2088.41" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="8.0.0-rc.2.23479.10" /> <PackageVersion Include="Microsoft.Windows.Compatibility" Version="8.0.0-rc.2.23479.10" />
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" /> <PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
<!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. --> <!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. -->

View File

@ -335,7 +335,7 @@ SOFTWARE.
- Microsoft.Extensions.Logging 8.0.0-rc.2.23479.6 - Microsoft.Extensions.Logging 8.0.0-rc.2.23479.6
- Microsoft.NET.Test.Sdk 17.6.3 - Microsoft.NET.Test.Sdk 17.6.3
- Microsoft.Toolkit.Uwp.Notifications 7.1.2 - Microsoft.Toolkit.Uwp.Notifications 7.1.2
- Microsoft.Web.WebView2 1.0.1722.45 - Microsoft.Web.WebView2 1.0.2088.41
- Microsoft.Windows.Compatibility 8.0.0-rc.2.23479.10 - Microsoft.Windows.Compatibility 8.0.0-rc.2.23479.10
- Microsoft.Windows.CsWin32 0.2.46-beta - Microsoft.Windows.CsWin32 0.2.46-beta
- Microsoft.Windows.CsWinRT 2.0.3 - Microsoft.Windows.CsWinRT 2.0.3

View File

@ -1,10 +1,7 @@
# Keyboard Manager UI # Keyboard Manager UI
## Table of Contents: ## Table of Contents:
1. [C++ XAML Islands](#c-xaml-islands) 1. [XAML Implementation](#xaml-implementation)
1. [Debugging exceptions in XAML Islands](#debugging-exceptions-in-xaml-islands)
2. [Build times](#build-times)
3. [Setting custom backgrounds for Xaml Controls using brushes](#setting-custom-backgrounds-for-xaml-controls-using-brushes)
2. [UI Structure](#ui-structure) 2. [UI Structure](#ui-structure)
3. [EditKeyboardWindow / EditShortcutsWindow](#editkeyboardwindow--editshortcutswindow) 3. [EditKeyboardWindow / EditShortcutsWindow](#editkeyboardwindow--editshortcutswindow)
1. [OK and Cancel button](#ok-and-cancel-button) 1. [OK and Cancel button](#ok-and-cancel-button)
@ -17,28 +14,18 @@
2. [Single Key ComboBox Selection Handler](#single-key-combobox-selection-handler) 2. [Single Key ComboBox Selection Handler](#single-key-combobox-selection-handler)
3. [Shortcut ComboBox Selection Handler](#shortcut-combobox-selection-handler) 3. [Shortcut ComboBox Selection Handler](#shortcut-combobox-selection-handler)
## C++ XAML Islands ## XAML Implementation
The KBM UI is implemented as a C++ XAML Island, but all the controls are implemented in code behind rather than .xaml and .xaml.cs files. This was done as per a XAML Island Code sample and it didn't require a separate UWP project, which could be limited in terms of using hooks. There is a [tech debt item](https://github.com/microsoft/PowerToys/issues/2027) for moving this to XAML. The reason it wasn't implemented in the C# Settings was because it required communication with the low level hook thread, which could be too slow if IPC is used, since the UI needs to update on every key event. The KBM UI was originally implemented as a XAML Island, but in order to easily support Mica, which is [still an issue](https://github.com/microsoft/microsoft-ui-xaml/issues/5319), the [`XamlBridge`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp) was rewritten to use a [`FrameworkView`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L47C11-L49) object which is how a traditional UWP app behaves:
1. A `CoreWindow` is created by [calling a function inside of `Windows.UI.dll` with an ordinal number of `1500`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L35-L42).
2. A [stubbed implementation of `CoreApplicationView`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L10-L18) was created.
3. Then [both objects are passed on to the `FrameworkView`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L47-L49) to initialize the XAML framework.
4. Lastly, the `CoreWindow` is [attached to the editor window](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/XamlBridge2.cpp#L54-L61) and its `HWND` is used in-place of `DesktopWindowXamlSource`'s.
**Note:** For functions which take a XAML component as argument, pass it by value and not by reference. This is because `winrt` WinUI classes store their own internal references, so they are supposed to be passed by value (and internally ref counts are incremented). Passing by reference can lead to weird behavior where the object is `null`. Mica is then achieved by calling [`BackdropMaterial::SetApplyToRootOrPageBackground()`](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp#L388-L400) in both of the editor windows, or falls back to the `ApplicationPageBackgroundThemeBrush` background if Mica isn't available.
The windows are [created as C++ windows](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L128-L140) and the window sizes are set to default by [scaling them as per DPI](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L120-L126) using the `DPIAware::Convert` API from common lib. Since the UI is launched on a new thread, the window may not be in the foreground, so [we call `SetForegroundWindow`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L146-L150). The UI was also updated to use WinUI 2.8 to match the look and feel of the Fluent design language of Windows 11 and the rest of PowerToys. There has been talk about [migrating the implementation to XAML files instead of code-behind](https://github.com/microsoft/PowerToys/issues/2027) and [utilizing WinUI 3 going forward](https://github.com/microsoft/PowerToys/issues/15870). More about the update can be read in [here](https://github.com/microsoft/PowerToys/pull/28473).
`DesktopWindowXamlSource` has to be declared and [it is initialized](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L159-L162) using the [`XamlBridge`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/XamlBridge.cpp), and [a second window handle](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L161-L162) is generated for the internal Xaml Island window. Most of the code was based on the [Xaml Island Sample](https://github.com/microsoft/Xaml-Islands-Samples/blob/master/Samples/Win32/SampleCppApp/XamlBridge.cpp). The `XamlBridge` class contains code which handles initializing the Xaml Island containers as well as handling special messages like keyboard navigation, and focus between islands and between the C++ window and the island. It also has methods for clearing the xaml islands and closing the window. [**Link to the original documentation**](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md#c-xaml-islands)
Once the UI controls are created, the parent container is set as the content for the `DesktopWindowXamlSource` and the `XamlBridge.MessageLoop` is executed. Messages are processed by the C++ window handler like [`EditKeyboardWindowProc`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L364-L404). The general structure we use for this is, for any `WM_PAINT` or `WM_SIZE` message we resize the Xaml Island window. For `WM_GETMINMAXINFO` we set minimum widths so that the window cannot be resized beyond a minimum height and width. This is done to prevent the WinUI elements from overlapping and getting cropped. If it is neither of these cases we send the message to the [`XamlBridge.MessageHandler`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/XamlBridge.cpp#L291-L301) which handles Destroy, Activation and Focus. If `WM_NCDESTROY` is received when the `XamlBridge` is `nullptr`, the window thread is terminated.
**Note:** `ContentDialog` in Xaml Islands requires manually settings a `XamlRoot`. This can generally be done by passing the XamlRoot from a component in the main window, such as the button used to open the dialog ([`sender.as<Button>().XamlRoot()`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.cpp#L31-L32)). [These docs]((https://learn.microsoft.com/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands)) have more details about this.
### Debugging exceptions in XAML Islands
Sometimes if an exception occurs in XAML Islands, the stack trace may not always point to the correct code causing the exception and instead it will point to the Xaml Island message loop. In these cases the output window in VS will generally show the correct exception.
### Build times
C++ Xaml Islands generally take several minutes to build because the `pch` which contains the WinUI headers takes longer to build and compiles to a file of several GBs. To minimize the build times, multi-processor compilation within the projects have been enabled (files are distributed for compilation to the processors), and references to the Xaml headers have been removed from the .h headers files as much as possible. Since several classes of ours had class members with UI controls like `StackPanel` (which requires definitions of the classes in order to compile), we worked around this by declaring them as `IInspectable` (the equivalent of an object pointer in winrt), and initializing them to the actual control like `StackPanel` in the constructor and accessing all their member functions by inline typecasting (for `IInspectable x;` we do `x = StackPanel();` and `x.as<StackPanel>().MemberFunction()`). Check [this](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.cpp#L19-L25) for this type of usage in `ShortcutControl`.
### Setting custom backgrounds for Xaml Controls using brushes
To access the brushes available on C# Xaml, it has to be done with the `Resources.Lookup` syntax:
`primaryButton.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseMediumLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());`
## UI Structure ## UI Structure
The KBM UI consists of a [`Grid` with several columns](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L200-L218). Rows are added dynamically when [the add button is pressed](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L305-L309). [A vector of vector of unique pointers to `SingleKeyRemapControl`/`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L248-L249) is created so that references to the UI components and their data are not lost until the window is closed. [`SingleKeyRemapControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp) is the UI class for each row of the Remap keys table, and [`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/ShortcutControl.cpp) is the UI class for each row of the Remap shortcuts table. [`KeyDropDownControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp) is used for handling the ComboBox operations. Each of these two classes [have vectors of unique pointers to the `KeyDropDownControl` objects](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.h#L44-L45) so that references to the objects are active until the control is deleted. The KBM UI consists of a [`Grid` with several columns](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L200-L218). Rows are added dynamically when [the add button is pressed](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L305-L309). [A vector of vector of unique pointers to `SingleKeyRemapControl`/`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L248-L249) is created so that references to the UI components and their data are not lost until the window is closed. [`SingleKeyRemapControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp) is the UI class for each row of the Remap keys table, and [`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/ShortcutControl.cpp) is the UI class for each row of the Remap shortcuts table. [`KeyDropDownControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp) is used for handling the ComboBox operations. Each of these two classes [have vectors of unique pointers to the `KeyDropDownControl` objects](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.h#L44-L45) so that references to the objects are active until the control is deleted.

View File

@ -1,6 +1,6 @@
# Developer Preview (Monaco) # Developer Preview (Monaco)
Developer preview is based on [Microsofts Monaco Editor](https://microsoft.github.io/monaco-editor/) which is maintained by the Visual Studio Code team. Developer preview is based on [Microsoft's Monaco Editor](https://microsoft.github.io/monaco-editor/) which is maintained by the Visual Studio Code team.
## Update monaco editor ## Update monaco editor

View File

@ -17,6 +17,14 @@
<RegistryValue Type="string" Name="Module_KeyboardManager_Editor" Value="" KeyPath="yes"/> <RegistryValue Type="string" Name="Module_KeyboardManager_Editor" Value="" KeyPath="yes"/>
</RegistryKey> </RegistryKey>
<File Source="$(var.BinDir)KeyboardManagerEditor\PowerToys.KeyboardManagerEditor.exe" /> <File Source="$(var.BinDir)KeyboardManagerEditor\PowerToys.KeyboardManagerEditor.exe" />
<File Source="$(var.BinDir)KeyboardManagerEditor\Microsoft.Toolkit.Win32.UI.XamlHost.dll" />
<File Source="$(var.BinDir)KeyboardManagerEditor\Microsoft.UI.Xaml.dll" />
<File Source="$(var.BinDir)KeyboardManagerEditor\msvcp140_app.dll" />
<File Source="$(var.BinDir)KeyboardManagerEditor\resources.pri" />
<File Source="$(var.BinDir)KeyboardManagerEditor\vcruntime140_app.dll" />
<?if $(sys.BUILDARCH) = x64 ?>
<File Source="$(var.BinDir)KeyboardManagerEditor\vcruntime140_1_app.dll" />
<?endif ?>
</Component> </Component>
</DirectoryRef> </DirectoryRef>

View File

@ -24,7 +24,7 @@ namespace Microsoft.VariantAssignment.Contract
public bool EnableCaching { get; set; } public bool EnableCaching { get; set; }
/// <summary> /// <summary>
/// Gets or sets the the maximum time a cached variant assignment response may be used without re-validating. /// Gets or sets the maximum time a cached variant assignment response may be used without re-validating.
/// </summary> /// </summary>
public TimeSpan ResponseCacheTime { get; set; } public TimeSpan ResponseCacheTime { get; set; }
} }

View File

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace ManagedCommon
{
public enum ModuleType
{
AlwaysOnTop,
Awake,
ColorPicker,
CropAndLock,
EnvironmentVariables,
FancyZones,
FileLocksmith,
FindMyMouse,
Hosts,
ImageResizer,
KeyboardManager,
MouseHighlighter,
MouseJump,
MousePointerCrosshairs,
MouseWithoutBorders,
PastePlain,
Peek,
PowerRename,
PowerLauncher,
PowerAccent,
RegistryPreview,
MeasureTool,
ShortcutGuide,
PowerOCR,
}
}

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation. <!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. --> Licensed under the MIT License. -->
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.4" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions"> <policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.5" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyNamespaces> <policyNamespaces>
<target prefix="powertoys" namespace="Microsoft.Policies.PowerToys" /> <target prefix="powertoys" namespace="Microsoft.Policies.PowerToys" />
</policyNamespaces> </policyNamespaces>
<resources minRequiredRevision="1.4"/><!-- Last changed with PowerToys v0.75.0 --> <resources minRequiredRevision="1.5"/><!-- Last changed with PowerToys v0.75.1 -->
<supportedOn> <supportedOn>
<definitions> <definitions>
<definition name="SUPPORTED_POWERTOYS_0_64_0" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0)"/> <definition name="SUPPORTED_POWERTOYS_0_64_0" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0)"/>
@ -78,6 +78,16 @@
<decimal value="0" /> <decimal value="0" />
</disabledValue> </disabledValue>
</policy> </policy>
<policy name="ConfigureEnabledUtilityEnvironmentVariables" class="Both" displayName="$(string.ConfigureEnabledUtilityEnvironmentVariables)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityEnvironmentVariables">
<parentCategory ref="PowerToys" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_75_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="ConfigureEnabledUtilityFancyZones" class="Both" displayName="$(string.ConfigureEnabledUtilityFancyZones)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityFancyZones"> <policy name="ConfigureEnabledUtilityFancyZones" class="Both" displayName="$(string.ConfigureEnabledUtilityFancyZones)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityFancyZones">
<parentCategory ref="PowerToys" /> <parentCategory ref="PowerToys" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_64_0" /> <supportedOn ref="SUPPORTED_POWERTOYS_0_64_0" />

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation. <!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. --> Licensed under the MIT License. -->
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.4" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions"> <policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.5" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<displayName>PowerToys</displayName> <displayName>PowerToys</displayName>
<description>PowerToys</description> <description>PowerToys</description>
<resources> <resources>
@ -112,6 +112,7 @@ Note: Changes require a restart of PowerToys Run.
<string id="ConfigureEnabledUtilityAwake">Awake: Configure enabled state</string> <string id="ConfigureEnabledUtilityAwake">Awake: Configure enabled state</string>
<string id="ConfigureEnabledUtilityColorPicker">Color Picker: Configure enabled state</string> <string id="ConfigureEnabledUtilityColorPicker">Color Picker: Configure enabled state</string>
<string id="ConfigureEnabledUtilityCropAndLock">Crop And Lock: Configure enabled state</string> <string id="ConfigureEnabledUtilityCropAndLock">Crop And Lock: Configure enabled state</string>
<string id="ConfigureEnabledUtilityEnvironmentVariables">Environment Variables: Configure enabled state</string>
<string id="ConfigureEnabledUtilityFancyZones">FancyZones: Configure enabled state</string> <string id="ConfigureEnabledUtilityFancyZones">FancyZones: Configure enabled state</string>
<string id="ConfigureEnabledUtilityFileLocksmith">File Locksmith: Configure enabled state</string> <string id="ConfigureEnabledUtilityFileLocksmith">File Locksmith: Configure enabled state</string>
<string id="ConfigureEnabledUtilityFileExplorerSVGPreview">SVG file preview: Configure enabled state</string> <string id="ConfigureEnabledUtilityFileExplorerSVGPreview">SVG file preview: Configure enabled state</string>

View File

@ -87,12 +87,29 @@ void ReparentCropAndLockWindow::CropAndLock(HWND windowToCrop, RECT cropRect)
DisconnectTarget(); DisconnectTarget();
m_currentTarget = windowToCrop; m_currentTarget = windowToCrop;
// Adjust the crop rect to be in the window space as reported by win32k // Save original state
SaveOriginalState();
RECT windowRect = {}; RECT windowRect = {};
winrt::check_bool(GetWindowRect(m_currentTarget, &windowRect)); winrt::check_bool(GetWindowRect(m_currentTarget, &windowRect));
auto clientRect = ClientAreaInScreenSpace(m_currentTarget); auto clientRect = ClientAreaInScreenSpace(m_currentTarget);
WINDOWPLACEMENT windowPlacement = { sizeof(windowPlacement) };
winrt::check_bool(GetWindowPlacement(m_currentTarget, &windowPlacement));
bool isMaximized = (windowPlacement.showCmd == SW_SHOWMAXIMIZED);
auto diffX = clientRect.left - windowRect.left; auto diffX = clientRect.left - windowRect.left;
auto diffY = clientRect.top - windowRect.top; auto diffY = clientRect.top - windowRect.top;
if (isMaximized)
{
MONITORINFO mi = { sizeof(mi) };
winrt::check_bool(GetMonitorInfo(MonitorFromWindow(m_currentTarget, MONITOR_DEFAULTTONEAREST), &mi));
diffX = mi.rcWork.left - windowRect.left;
diffY = mi.rcWork.top - windowRect.top;
}
auto adjustedCropRect = cropRect; auto adjustedCropRect = cropRect;
adjustedCropRect.left += diffX; adjustedCropRect.left += diffX;
adjustedCropRect.top += diffY; adjustedCropRect.top += diffY;
@ -100,8 +117,6 @@ void ReparentCropAndLockWindow::CropAndLock(HWND windowToCrop, RECT cropRect)
adjustedCropRect.bottom += diffY; adjustedCropRect.bottom += diffY;
cropRect = adjustedCropRect; cropRect = adjustedCropRect;
// Save the previous position of the target so that we can restore it.
m_previousPosition = { windowRect.left, windowRect.top };
auto newX = adjustedCropRect.left + windowRect.left; auto newX = adjustedCropRect.left + windowRect.left;
auto newY = adjustedCropRect.top + windowRect.top; auto newY = adjustedCropRect.top + windowRect.top;
@ -153,11 +168,53 @@ void ReparentCropAndLockWindow::DisconnectTarget()
m_currentTarget = nullptr; m_currentTarget = nullptr;
return; return;
} }
winrt::check_bool(SetWindowPos(m_currentTarget, nullptr, m_previousPosition.x, m_previousPosition.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_FRAMECHANGED));
SetParent(m_currentTarget, nullptr); RestoreOriginalState();
auto targetStyle = static_cast<DWORD>(GetWindowLongPtrW(m_currentTarget, GWL_STYLE)); }
targetStyle &= ~WS_CHILD; }
SetWindowLongPtrW(m_currentTarget, GWL_STYLE, targetStyle);
m_currentTarget = nullptr; void ReparentCropAndLockWindow::SaveOriginalState()
{
if (m_currentTarget != nullptr)
{
originalPlacement.length = sizeof(WINDOWPLACEMENT);
winrt::check_bool(GetWindowPlacement(m_currentTarget, &originalPlacement));
originalExStyle = GetWindowLongPtr(m_currentTarget, GWL_EXSTYLE);
winrt::check_bool(originalExStyle != 0 || GetLastError() == ERROR_SUCCESS);
originalStyle = GetWindowLongPtr(m_currentTarget, GWL_STYLE);
winrt::check_bool(originalStyle != 0 || GetLastError() == ERROR_SUCCESS);
winrt::check_bool(GetWindowRect(m_currentTarget, &originalRect));
}
}
void ReparentCropAndLockWindow::RestoreOriginalState()
{
if (m_currentTarget)
{
// Restore window position and dimensions
int width = originalRect.right - originalRect.left;
int height = originalRect.bottom - originalRect.top;
winrt::check_bool(SetWindowPos(m_currentTarget, nullptr, originalRect.left, originalRect.top, width, height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED));
SetParent(m_currentTarget, nullptr);
// Restore the original placement
if (originalPlacement.showCmd != SW_SHOWMAXIMIZED)
{
originalPlacement.showCmd = SW_RESTORE;
}
winrt::check_bool(SetWindowPlacement(m_currentTarget, &originalPlacement));
// Set the original extended style and style
originalStyle &= ~WS_CHILD;
LONG_PTR prevExStyle = SetWindowLongPtr(m_currentTarget, GWL_EXSTYLE, originalExStyle);
winrt::check_bool(prevExStyle != 0 || GetLastError() == ERROR_SUCCESS);
LONG_PTR prevStyle = SetWindowLongPtr(m_currentTarget, GWL_STYLE, originalStyle);
winrt::check_bool(prevStyle != 0 || GetLastError() == ERROR_SUCCESS);
} }
} }

View File

@ -19,11 +19,17 @@ private:
void Hide(); void Hide();
void DisconnectTarget(); void DisconnectTarget();
void SaveOriginalState();
void RestoreOriginalState();
private: private:
HWND m_currentTarget = nullptr; HWND m_currentTarget = nullptr;
POINT m_previousPosition = {};
std::unique_ptr<ChildWindow> m_childWindow; std::unique_ptr<ChildWindow> m_childWindow;
bool m_destroyed = false; bool m_destroyed = false;
std::function<void(HWND)> m_closedCallback; std::function<void(HWND)> m_closedCallback;
LONG_PTR originalExStyle = 0;
LONG_PTR originalStyle = 0;
WINDOWPLACEMENT originalPlacement = { sizeof(WINDOWPLACEMENT) };
RECT originalRect = {};
}; };

View File

@ -5,6 +5,7 @@
using System.IO.Abstractions.TestingHelpers; using System.IO.Abstractions.TestingHelpers;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Hosts.Exceptions;
using Hosts.Helpers; using Hosts.Helpers;
using Hosts.Models; using Hosts.Models;
using Hosts.Settings; using Hosts.Settings;
@ -18,11 +19,13 @@ namespace Hosts.Tests
[TestClass] [TestClass]
public class HostsServiceTest public class HostsServiceTest
{ {
private static Mock<IUserSettings> _userSettings;
private static Mock<IElevationHelper> _elevationHelper; private static Mock<IElevationHelper> _elevationHelper;
[ClassInitialize] [ClassInitialize]
public static void ClassInitialize(TestContext context) public static void ClassInitialize(TestContext context)
{ {
_userSettings = new Mock<IUserSettings>();
_elevationHelper = new Mock<IElevationHelper>(); _elevationHelper = new Mock<IElevationHelper>();
_elevationHelper.Setup(m => m.IsElevated).Returns(true); _elevationHelper.Setup(m => m.IsElevated).Returns(true);
} }
@ -31,8 +34,7 @@ namespace Hosts.Tests
public void Hosts_Exists() public void Hosts_Exists()
{ {
var fileSystem = new CustomMockFileSystem(); var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>(); var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(string.Empty)); fileSystem.AddFile(service.HostsFilePath, new MockFileData(string.Empty));
var result = service.Exists(); var result = service.Exists();
@ -43,8 +45,7 @@ namespace Hosts.Tests
public void Hosts_Not_Exists() public void Hosts_Not_Exists()
{ {
var fileSystem = new CustomMockFileSystem(); var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>(); var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
var result = service.Exists(); var result = service.Exists();
Assert.IsFalse(result); Assert.IsFalse(result);
@ -65,8 +66,7 @@ namespace Hosts.Tests
"; ";
var fileSystem = new CustomMockFileSystem(); var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>(); var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content)); fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var data = await service.ReadAsync(); var data = await service.ReadAsync();
@ -91,8 +91,7 @@ namespace Hosts.Tests
"; ";
var fileSystem = new CustomMockFileSystem(); var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>(); var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content)); fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var data = await service.ReadAsync(); var data = await service.ReadAsync();
@ -118,8 +117,7 @@ namespace Hosts.Tests
"; ";
var fileSystem = new CustomMockFileSystem(); var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>(); var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content)); fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var data = await service.ReadAsync(); var data = await service.ReadAsync();
@ -138,9 +136,7 @@ namespace Hosts.Tests
public async Task Empty_Hosts() public async Task Empty_Hosts()
{ {
var fileSystem = new CustomMockFileSystem(); var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>(); var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(string.Empty)); fileSystem.AddFile(service.HostsFilePath, new MockFileData(string.Empty));
await service.WriteAsync(string.Empty, Enumerable.Empty<Entry>()); await service.WriteAsync(string.Empty, Enumerable.Empty<Entry>());
@ -203,7 +199,6 @@ namespace Hosts.Tests
var fileSystem = new CustomMockFileSystem(); var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>(); var userSettings = new Mock<IUserSettings>();
userSettings.Setup(m => m.AdditionalLinesPosition).Returns(HostsAdditionalLinesPosition.Bottom); userSettings.Setup(m => m.AdditionalLinesPosition).Returns(HostsAdditionalLinesPosition.Bottom);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object); var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content)); fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
@ -228,8 +223,7 @@ namespace Hosts.Tests
"; ";
var fileSystem = new CustomMockFileSystem(); var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>(); var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content)); fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var data = await service.ReadAsync(); var data = await service.ReadAsync();
@ -243,12 +237,37 @@ namespace Hosts.Tests
public async Task Save_NotRunningElevatedException() public async Task Save_NotRunningElevatedException()
{ {
var fileSystem = new CustomMockFileSystem(); var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>();
var elevationHelper = new Mock<IElevationHelper>(); var elevationHelper = new Mock<IElevationHelper>();
elevationHelper.Setup(m => m.IsElevated).Returns(false); elevationHelper.Setup(m => m.IsElevated).Returns(false);
var service = new HostsService(fileSystem, userSettings.Object, elevationHelper.Object); var service = new HostsService(fileSystem, _userSettings.Object, elevationHelper.Object);
await Assert.ThrowsExceptionAsync<NotRunningElevatedException>(async () => await service.WriteAsync("# Empty hosts file", Enumerable.Empty<Entry>())); await Assert.ThrowsExceptionAsync<NotRunningElevatedException>(async () => await service.WriteAsync("# Empty hosts file", Enumerable.Empty<Entry>()));
} }
[TestMethod]
public async Task Save_ReadOnlyHostsException()
{
var fileSystem = new CustomMockFileSystem();
var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
var hostsFile = new MockFileData(string.Empty);
hostsFile.Attributes = System.IO.FileAttributes.ReadOnly;
fileSystem.AddFile(service.HostsFilePath, hostsFile);
await Assert.ThrowsExceptionAsync<ReadOnlyHostsException>(async () => await service.WriteAsync("# Empty hosts file", Enumerable.Empty<Entry>()));
}
[TestMethod]
public void Remove_ReadOnly()
{
var fileSystem = new CustomMockFileSystem();
var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
var hostsFile = new MockFileData(string.Empty);
hostsFile.Attributes = System.IO.FileAttributes.ReadOnly;
fileSystem.AddFile(service.HostsFilePath, hostsFile);
service.RemoveReadOnly();
var readOnly = fileSystem.FileInfo.FromFileName(service.HostsFilePath).Attributes.HasFlag(System.IO.FileAttributes.ReadOnly);
Assert.IsFalse(readOnly);
}
} }
} }

View File

@ -4,7 +4,7 @@
using System; using System;
namespace Hosts.Helpers namespace Hosts.Exceptions
{ {
public class NotRunningElevatedException : Exception public class NotRunningElevatedException : Exception
{ {

View File

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Hosts.Exceptions
{
public class ReadOnlyHostsException : Exception
{
}
}

View File

@ -13,6 +13,7 @@ using System.Net.NetworkInformation;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Hosts.Exceptions;
using Hosts.Models; using Hosts.Models;
using Hosts.Settings; using Hosts.Settings;
using ManagedCommon; using ManagedCommon;
@ -129,6 +130,11 @@ namespace Hosts.Helpers
throw new NotRunningElevatedException(); throw new NotRunningElevatedException();
} }
if (_fileSystem.FileInfo.FromFileName(HostsFilePath).IsReadOnly)
{
throw new ReadOnlyHostsException();
}
var lines = new List<string>(); var lines = new List<string>();
if (entries.Any()) if (entries.Any())
@ -288,6 +294,15 @@ namespace Hosts.Helpers
} }
} }
public void RemoveReadOnly()
{
var fileInfo = _fileSystem.FileInfo.FromFileName(HostsFilePath);
if (fileInfo.IsReadOnly)
{
fileInfo.IsReadOnly = false;
}
}
public void Dispose() public void Dispose()
{ {
Dispose(disposing: true); Dispose(disposing: true);

View File

@ -24,5 +24,7 @@ namespace Hosts.Helpers
void CleanupBackup(); void CleanupBackup();
void OpenHostsFile(); void OpenHostsFile();
void RemoveReadOnly();
} }
} }

View File

@ -377,7 +377,15 @@
IsOpen="{x:Bind ViewModel.Error, Mode=TwoWay}" IsOpen="{x:Bind ViewModel.Error, Mode=TwoWay}"
Message="{x:Bind ViewModel.ErrorMessage, Mode=TwoWay}" Message="{x:Bind ViewModel.ErrorMessage, Mode=TwoWay}"
Severity="Error" Severity="Error"
Visibility="{x:Bind ViewModel.Error, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}}" /> Visibility="{x:Bind ViewModel.Error, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}}">
<InfoBar.ActionButton>
<Button
x:Uid="MakeWritable"
HorizontalAlignment="Right"
Command="{x:Bind ViewModel.OverwriteHostsCommand}"
Visibility="{x:Bind ViewModel.IsReadOnly, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}}" />
</InfoBar.ActionButton>
</InfoBar>
<InfoBar <InfoBar
x:Uid="FileChanged" x:Uid="FileChanged"
Margin="0,8,0,0" Margin="0,8,0,0"
@ -385,7 +393,10 @@
Severity="Informational" Severity="Informational"
Visibility="{x:Bind ViewModel.FileChanged, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}}"> Visibility="{x:Bind ViewModel.FileChanged, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}}">
<InfoBar.ActionButton> <InfoBar.ActionButton>
<Button x:Uid="Reload" Command="{x:Bind ViewModel.ReadHostsCommand}" /> <Button
x:Uid="Reload"
HorizontalAlignment="Right"
Command="{x:Bind ViewModel.ReadHostsCommand}" />
</InfoBar.ActionButton> </InfoBar.ActionButton>
</InfoBar> </InfoBar>
</StackPanel> </StackPanel>

View File

@ -228,6 +228,10 @@
<value>The hosts file cannot be saved because the program isn't running as administrator.</value> <value>The hosts file cannot be saved because the program isn't running as administrator.</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment> <comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data> </data>
<data name="FileSaveError_ReadOnly" xml:space="preserve">
<value>The hosts file cannot be saved because it is read-only.</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data>
<data name="FilterBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve"> <data name="FilterBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Filters</value> <value>Filters</value>
</data> </data>
@ -246,6 +250,9 @@
<value>Hosts</value> <value>Hosts</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment> <comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data> </data>
<data name="MakeWritable.Content" xml:space="preserve">
<value>Make writable</value>
</data>
<data name="MoveDown.Text" xml:space="preserve"> <data name="MoveDown.Text" xml:space="preserve">
<value>Move down</value> <value>Move down</value>
</data> </data>

View File

@ -15,6 +15,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.WinUI; using CommunityToolkit.WinUI;
using CommunityToolkit.WinUI.Collections; using CommunityToolkit.WinUI.Collections;
using Hosts.Exceptions;
using Hosts.Helpers; using Hosts.Helpers;
using Hosts.Models; using Hosts.Models;
using Hosts.Settings; using Hosts.Settings;
@ -48,6 +49,9 @@ namespace Hosts.ViewModels
[ObservableProperty] [ObservableProperty]
private string _errorMessage; private string _errorMessage;
[ObservableProperty]
private bool _isReadOnly;
[ObservableProperty] [ObservableProperty]
private bool _fileChanged; private bool _fileChanged;
@ -262,6 +266,13 @@ namespace Hosts.ViewModels
_hostsService.OpenHostsFile(); _hostsService.OpenHostsFile();
} }
[RelayCommand]
public void OverwriteHosts()
{
_hostsService.RemoveReadOnly();
_ = Task.Run(SaveAsync);
}
public void Dispose() public void Dispose()
{ {
Dispose(disposing: true); Dispose(disposing: true);
@ -374,6 +385,7 @@ namespace Hosts.ViewModels
{ {
bool error = true; bool error = true;
string errorMessage = string.Empty; string errorMessage = string.Empty;
bool isReadOnly = false;
try try
{ {
@ -385,6 +397,12 @@ namespace Hosts.ViewModels
var resourceLoader = ResourceLoaderInstance.ResourceLoader; var resourceLoader = ResourceLoaderInstance.ResourceLoader;
errorMessage = resourceLoader.GetString("FileSaveError_NotElevated"); errorMessage = resourceLoader.GetString("FileSaveError_NotElevated");
} }
catch (ReadOnlyHostsException)
{
isReadOnly = true;
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
errorMessage = resourceLoader.GetString("FileSaveError_ReadOnly");
}
catch (IOException ex) when ((ex.HResult & 0x0000FFFF) == 32) catch (IOException ex) when ((ex.HResult & 0x0000FFFF) == 32)
{ {
// There are some edge cases where a big hosts file is being locked by svchost.exe https://github.com/microsoft/PowerToys/issues/28066 // There are some edge cases where a big hosts file is being locked by svchost.exe https://github.com/microsoft/PowerToys/issues/28066
@ -402,6 +420,7 @@ namespace Hosts.ViewModels
{ {
Error = error; Error = error;
ErrorMessage = errorMessage; ErrorMessage = errorMessage;
IsReadOnly = isReadOnly;
}); });
} }

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Project configurations --> <!-- Project configurations -->
<Import Project="..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props" Condition="Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" /> <Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup> <PropertyGroup>
<NoWarn>81010002</NoWarn> <NoWarn>81010002</NoWarn>
@ -98,7 +100,7 @@
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>Display.lib;shcore.lib;Dbghelp.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Display.lib;shcore.lib;Dbghelp.lib;dwmapi.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(ConfigurationName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(ConfigurationName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -109,7 +111,7 @@
<Link> <Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>Display.lib;shcore.lib;Dbghelp.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Display.lib;shcore.lib;Dbghelp.lib;dwmapi.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(ConfigurationName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(ConfigurationName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -160,6 +162,10 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" /> <Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets')" />
</ImportGroup> </ImportGroup>
<Import Project="..\..\..\..\deps\spdlog.props" /> <Import Project="..\..\..\..\deps\spdlog.props" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild"> <Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
@ -171,5 +177,15 @@
</PropertyGroup> </PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" /> <Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" /> <Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<Target Name="FakeResourcesPriMerge" BeforeTargets="FinalizeBuildStatus" DependsOnTargets="CopyFilesToOutputDirectory">
<Message Text="Renaming Microsoft.UI.Xaml.pri to resources.pri" />
<Move SourceFiles="$(OutDir)\Microsoft.UI.Xaml.pri" DestinationFiles="$(OutDir)\resources.pri" />
</Target> </Target>
</Project> </Project>

View File

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.8.2-prerelease.220830001" targetFramework="native" />
<package id="Microsoft.VCRTForwarders.140" version="1.0.7" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.2088.41" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.221104.6" targetFramework="native" /> <package id="Microsoft.Windows.CppWinRT" version="2.0.221104.6" targetFramework="native" />
</packages> </packages>

View File

@ -15,7 +15,7 @@
#include "EditKeyboardWindow.h" #include "EditKeyboardWindow.h"
#include "SingleKeyRemapControl.h" #include "SingleKeyRemapControl.h"
#include "KeyDropDownControl.h" #include "KeyDropDownControl.h"
#include "XamlBridge.h" #include "XamlBridge2.h"
#include "Styles.h" #include "Styles.h"
#include "Dialog.h" #include "Dialog.h"
#include "LoadingAndSavingRemappingHelper.h" #include "LoadingAndSavingRemappingHelper.h"
@ -41,12 +41,12 @@ HWND hwndEditKeyboardNativeWindow = nullptr;
std::mutex editKeyboardWindowMutex; std::mutex editKeyboardWindowMutex;
// Stores a pointer to the Xaml Bridge object so that it can be accessed from the window procedure // Stores a pointer to the Xaml Bridge object so that it can be accessed from the window procedure
static XamlBridge* xamlBridgePtr = nullptr; static XamlBridge2* xamlBridgePtr = nullptr;
// Theming // Theming
ThemeListener theme_listener{}; static ThemeListener theme_listener{};
void handleTheme() static void handleTheme()
{ {
auto theme = theme_listener.AppTheme; auto theme = theme_listener.AppTheme;
auto isDark = theme == AppTheme::Dark; auto isDark = theme == AppTheme::Dark;
@ -137,7 +137,7 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
windowClass.lpfnWndProc = EditKeyboardWindowProc; windowClass.lpfnWndProc = EditKeyboardWindowProc;
windowClass.hInstance = hInst; windowClass.hInstance = hInst;
windowClass.lpszClassName = szWindowClass; windowClass.lpszClassName = szWindowClass;
windowClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW); windowClass.hbrBackground = CreateSolidBrush((ThemeHelpers::GetAppTheme() == AppTheme::Dark) ? 0x00000000 : 0x00FFFFFF);
windowClass.hIcon = static_cast<HICON>(LoadImageW( windowClass.hIcon = static_cast<HICON>(LoadImageW(
windowClass.hInstance, windowClass.hInstance,
MAKEINTRESOURCE(IDS_KEYBOARDMANAGER_ICON), MAKEINTRESOURCE(IDS_KEYBOARDMANAGER_ICON),
@ -196,17 +196,19 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
hwndEditKeyboardNativeWindow = _hWndEditKeyboardWindow; hwndEditKeyboardNativeWindow = _hWndEditKeyboardWindow;
hwndLock.unlock(); hwndLock.unlock();
// Hide icon and caption from title bar
const DWORD windowThemeOptionsMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
WTA_OPTIONS windowThemeOptions{ windowThemeOptionsMask, windowThemeOptionsMask };
SetWindowThemeAttribute(_hWndEditKeyboardWindow, WTA_NONCLIENT, &windowThemeOptions, sizeof(windowThemeOptions));
handleTheme(); handleTheme();
theme_listener.AddChangedHandler(handleTheme); theme_listener.AddChangedHandler(handleTheme);
// Create the xaml bridge object // Create the xaml bridge object
XamlBridge xamlBridge(_hWndEditKeyboardWindow); XamlBridge2 xamlBridge(_hWndEditKeyboardWindow);
// DesktopSource needs to be declared before the RelativePanel xamlContainer object to avoid errors
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource desktopSource;
// Create the desktop window xaml source object and set its content // Create the desktop window xaml source object and set its content
hWndXamlIslandEditKeyboardWindow = xamlBridge.InitDesktopWindowsXamlSource(desktopSource); hWndXamlIslandEditKeyboardWindow = xamlBridge.InitBridge();
// Set the pointer to the xaml bridge object // Set the pointer to the xaml bridge object
xamlBridgePtr = &xamlBridge; xamlBridgePtr = &xamlBridge;
@ -322,11 +324,8 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
// Add remap key button // Add remap key button
Windows::UI::Xaml::Controls::Button addRemapKey; Windows::UI::Xaml::Controls::Button addRemapKey;
FontIcon plusSymbol;
plusSymbol.FontFamily(Media::FontFamily(L"Segoe MDL2 Assets"));
plusSymbol.Glyph(L"\xE710");
addRemapKey.Content(plusSymbol);
addRemapKey.Margin({ 10, 10, 0, 25 }); addRemapKey.Margin({ 10, 10, 0, 25 });
addRemapKey.Style(AccentButtonStyle());
addRemapKey.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { addRemapKey.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, keyboardRemapControlObjects); SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, keyboardRemapControlObjects);
@ -337,14 +336,19 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
UIHelpers::SetFocusOnTypeButtonInLastRow(keyRemapTable, EditorConstants::RemapTableColCount); UIHelpers::SetFocusOnTypeButtonInLastRow(keyRemapTable, EditorConstants::RemapTableColCount);
}); });
// Remap key button content
StackPanel addRemapKeyContent;
addRemapKeyContent.Orientation(Orientation::Horizontal);
addRemapKeyContent.Spacing(10);
addRemapKeyContent.Children().Append(SymbolIcon(Symbol::Add));
TextBlock addRemapKeyText;
addRemapKeyText.Text(GET_RESOURCE_STRING(IDS_ADD_KEY_REMAP_BUTTON));
addRemapKeyContent.Children().Append(addRemapKeyText);
addRemapKey.Content(addRemapKeyContent);
// Set accessible name for the addRemapKey button // Set accessible name for the addRemapKey button
addRemapKey.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_ADD_KEY_REMAP_BUTTON))); addRemapKey.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_ADD_KEY_REMAP_BUTTON)));
// Add tooltip for add button which would appear on hover
ToolTip addRemapKeytoolTip;
addRemapKeytoolTip.Content(box_value(GET_RESOURCE_STRING(IDS_ADD_KEY_REMAP_BUTTON)));
ToolTipService::SetToolTip(addRemapKey, addRemapKeytoolTip);
// Header and example text at the top of the window // Header and example text at the top of the window
StackPanel helperText; StackPanel helperText;
helperText.Children().Append(keyRemapInfoHeader); helperText.Children().Append(keyRemapInfoHeader);
@ -381,7 +385,20 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
{ {
} }
desktopSource.Content(xamlContainer); UserControl xamlContent;
xamlContent.Content(xamlContainer);
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent(L"Windows.UI.Composition.ICompositionSupportsSystemBackdrop"))
{
// Apply Mica
muxc::BackdropMaterial::SetApplyToRootOrPageBackground(xamlContent, true);
}
else
{
// Mica isn't available
xamlContainer.Background(Application::Current().Resources().Lookup(box_value(L"ApplicationPageBackgroundThemeBrush")).as<Media::SolidColorBrush>());
}
Window::Current().Content(xamlContent);
////End XAML Island section ////End XAML Island section
if (_hWndEditKeyboardWindow) if (_hWndEditKeyboardWindow)
{ {
@ -400,9 +417,6 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
hwndEditKeyboardNativeWindow = nullptr; hwndEditKeyboardNativeWindow = nullptr;
keyboardManagerState.ResetUIState(); keyboardManagerState.ResetUIState();
keyboardManagerState.ClearRegisteredKeyDelays(); keyboardManagerState.ClearRegisteredKeyDelays();
// Cannot be done in WM_DESTROY because that causes crashes due to fatal app exit
xamlBridge.ClearXamlIslands();
} }
void CreateEditKeyboardWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration) void CreateEditKeyboardWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration)

View File

@ -13,9 +13,10 @@
#include "ShortcutControl.h" #include "ShortcutControl.h"
#include "Styles.h" #include "Styles.h"
#include "UIHelpers.h" #include "UIHelpers.h"
#include "XamlBridge.h" #include "XamlBridge2.h"
#include "ShortcutErrorType.h" #include "ShortcutErrorType.h"
#include "EditorConstants.h" #include "EditorConstants.h"
#include <common/Themes/theme_listener.h>
using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Foundation;
@ -34,7 +35,21 @@ HWND hwndEditShortcutsNativeWindow = nullptr;
std::mutex editShortcutsWindowMutex; std::mutex editShortcutsWindowMutex;
// Stores a pointer to the Xaml Bridge object so that it can be accessed from the window procedure // Stores a pointer to the Xaml Bridge object so that it can be accessed from the window procedure
static XamlBridge* xamlBridgePtr = nullptr; static XamlBridge2* xamlBridgePtr = nullptr;
// Theming
static ThemeListener theme_listener{};
static void handleTheme()
{
auto theme = theme_listener.AppTheme;
auto isDark = theme == AppTheme::Dark;
Logger::info(L"Theme is now {}", isDark ? L"Dark" : L"Light");
if (hwndEditShortcutsNativeWindow != nullptr)
{
ThemeHelpers::SetImmersiveDarkMode(hwndEditShortcutsNativeWindow, isDark);
}
}
static IAsyncAction OnClickAccept( static IAsyncAction OnClickAccept(
KBMEditor::KeyboardManagerState& keyboardManagerState, KBMEditor::KeyboardManagerState& keyboardManagerState,
@ -75,7 +90,7 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
windowClass.lpfnWndProc = EditShortcutsWindowProc; windowClass.lpfnWndProc = EditShortcutsWindowProc;
windowClass.hInstance = hInst; windowClass.hInstance = hInst;
windowClass.lpszClassName = szWindowClass; windowClass.lpszClassName = szWindowClass;
windowClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW); windowClass.hbrBackground = CreateSolidBrush((ThemeHelpers::GetAppTheme() == AppTheme::Dark) ? 0x00000000 : 0x00FFFFFF);
windowClass.hIcon = static_cast<HICON>(LoadImageW( windowClass.hIcon = static_cast<HICON>(LoadImageW(
windowClass.hInstance, windowClass.hInstance,
MAKEINTRESOURCE(IDS_KEYBOARDMANAGER_ICON), MAKEINTRESOURCE(IDS_KEYBOARDMANAGER_ICON),
@ -132,14 +147,19 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
hwndEditShortcutsNativeWindow = _hWndEditShortcutsWindow; hwndEditShortcutsNativeWindow = _hWndEditShortcutsWindow;
hwndLock.unlock(); hwndLock.unlock();
// Create the xaml bridge object // Hide icon and caption from title bar
XamlBridge xamlBridge(_hWndEditShortcutsWindow); const DWORD windowThemeOptionsMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
WTA_OPTIONS windowThemeOptions{ windowThemeOptionsMask, windowThemeOptionsMask };
SetWindowThemeAttribute(_hWndEditShortcutsWindow, WTA_NONCLIENT, &windowThemeOptions, sizeof(windowThemeOptions));
// DesktopSource needs to be declared before the RelativePanel xamlContainer object to avoid errors handleTheme();
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource desktopSource; theme_listener.AddChangedHandler(handleTheme);
// Create the xaml bridge object
XamlBridge2 xamlBridge(_hWndEditShortcutsWindow);
// Create the desktop window xaml source object and set its content // Create the desktop window xaml source object and set its content
hWndXamlIslandEditShortcutsWindow = xamlBridge.InitDesktopWindowsXamlSource(desktopSource); hWndXamlIslandEditShortcutsWindow = xamlBridge.InitBridge();
// Set the pointer to the xaml bridge object // Set the pointer to the xaml bridge object
xamlBridgePtr = &xamlBridge; xamlBridgePtr = &xamlBridge;
@ -276,11 +296,8 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
// Add shortcut button // Add shortcut button
Windows::UI::Xaml::Controls::Button addShortcut; Windows::UI::Xaml::Controls::Button addShortcut;
FontIcon plusSymbol;
plusSymbol.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
plusSymbol.Glyph(L"\xE710");
addShortcut.Content(plusSymbol);
addShortcut.Margin({ 10, 10, 0, 25 }); addShortcut.Margin({ 10, 10, 0, 25 });
addShortcut.Style(AccentButtonStyle());
addShortcut.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { addShortcut.Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ShortcutControl::AddNewShortcutControlRow(shortcutTable, keyboardRemapControlObjects); ShortcutControl::AddNewShortcutControlRow(shortcutTable, keyboardRemapControlObjects);
@ -291,14 +308,19 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
UIHelpers::SetFocusOnTypeButtonInLastRow(shortcutTable, EditorConstants::ShortcutTableColCount); UIHelpers::SetFocusOnTypeButtonInLastRow(shortcutTable, EditorConstants::ShortcutTableColCount);
}); });
// Remap shortcut button content
StackPanel addShortcutContent;
addShortcutContent.Orientation(Orientation::Horizontal);
addShortcutContent.Spacing(10);
addShortcutContent.Children().Append(SymbolIcon(Symbol::Add));
TextBlock addShortcutText;
addShortcutText.Text(GET_RESOURCE_STRING(IDS_ADD_SHORTCUT_BUTTON));
addShortcutContent.Children().Append(addShortcutText);
addShortcut.Content(addShortcutContent);
// Set accessible name for the add shortcut button // Set accessible name for the add shortcut button
addShortcut.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_ADD_SHORTCUT_BUTTON))); addShortcut.SetValue(Automation::AutomationProperties::NameProperty(), box_value(GET_RESOURCE_STRING(IDS_ADD_SHORTCUT_BUTTON)));
// Add tooltip for add button which would appear on hover
ToolTip addShortcuttoolTip;
addShortcuttoolTip.Content(box_value(GET_RESOURCE_STRING(IDS_ADD_SHORTCUT_BUTTON)));
ToolTipService::SetToolTip(addShortcut, addShortcuttoolTip);
// Header and example text at the top of the window // Header and example text at the top of the window
StackPanel helperText; StackPanel helperText;
helperText.Children().Append(shortcutRemapInfoHeader); helperText.Children().Append(shortcutRemapInfoHeader);
@ -334,7 +356,19 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
{ {
} }
desktopSource.Content(xamlContainer); UserControl xamlContent;
xamlContent.Content(xamlContainer);
if (Windows::Foundation::Metadata::ApiInformation::IsTypePresent(L"Windows.UI.Composition.ICompositionSupportsSystemBackdrop"))
{
// Apply Mica
muxc::BackdropMaterial::SetApplyToRootOrPageBackground(xamlContent, true);
}
else
{
// Mica isn't available
xamlContainer.Background(Application::Current().Resources().Lookup(box_value(L"ApplicationPageBackgroundThemeBrush")).as<Media::SolidColorBrush>());
}
Window::Current().Content(xamlContent);
////End XAML Island section ////End XAML Island section
if (_hWndEditShortcutsWindow) if (_hWndEditShortcutsWindow)
@ -353,9 +387,6 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
hwndEditShortcutsNativeWindow = nullptr; hwndEditShortcutsNativeWindow = nullptr;
keyboardManagerState.ResetUIState(); keyboardManagerState.ResetUIState();
keyboardManagerState.ClearRegisteredKeyDelays(); keyboardManagerState.ClearRegisteredKeyDelays();
// Cannot be done in WM_DESTROY because that causes crashes due to fatal app exit
xamlBridge.ClearXamlIslands();
} }
void CreateEditShortcutsWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration) void CreateEditShortcutsWindow(HINSTANCE hInst, KBMEditor::KeyboardManagerState& keyboardManagerState, MappingConfiguration& mappingConfiguration)

View File

@ -3,12 +3,12 @@
namespace EditorConstants namespace EditorConstants
{ {
// Default window sizes // Default window sizes
inline const int DefaultEditKeyboardWindowWidth = 800; inline const int DefaultEditKeyboardWindowWidth = 960;
inline const int DefaultEditKeyboardWindowHeight = 600; inline const int DefaultEditKeyboardWindowHeight = 600;
inline const int MinimumEditKeyboardWindowWidth = 500; inline const int MinimumEditKeyboardWindowWidth = 500;
inline const int MinimumEditKeyboardWindowHeight = 450; inline const int MinimumEditKeyboardWindowHeight = 450;
inline const int EditKeyboardTableMinWidth = 700; inline const int EditKeyboardTableMinWidth = 700;
inline const int DefaultEditShortcutsWindowWidth = 1050; inline const int DefaultEditShortcutsWindowWidth = 1410;
inline const int DefaultEditShortcutsWindowHeight = 600; inline const int DefaultEditShortcutsWindowHeight = 600;
inline const int MinimumEditShortcutsWindowWidth = 500; inline const int MinimumEditShortcutsWindowWidth = 500;
inline const int MinimumEditShortcutsWindowHeight = 500; inline const int MinimumEditShortcutsWindowHeight = 500;
@ -21,7 +21,9 @@ namespace EditorConstants
inline const long RemapTableArrowColIndex = 1; inline const long RemapTableArrowColIndex = 1;
inline const long RemapTableNewColIndex = 2; inline const long RemapTableNewColIndex = 2;
inline const long RemapTableRemoveColIndex = 3; inline const long RemapTableRemoveColIndex = 3;
inline const DWORD64 RemapTableDropDownWidth = 110; inline const DWORD64 RemapTableDropDownWidth = 160;
inline const DWORD64 RemapTableDropDownSpacing = 10;
inline const long RemapTargetColumnWidth = 3 * RemapTableDropDownWidth + 3 * RemapTableDropDownSpacing + 65;
// Shortcut table constants // Shortcut table constants
inline const long ShortcutTableColCount = 5; inline const long ShortcutTableColCount = 5;
@ -32,14 +34,14 @@ namespace EditorConstants
inline const long ShortcutTableTargetAppColIndex = 3; inline const long ShortcutTableTargetAppColIndex = 3;
inline const long ShortcutTableRemoveColIndex = 4; inline const long ShortcutTableRemoveColIndex = 4;
inline const long ShortcutArrowColumnWidth = 90; inline const long ShortcutArrowColumnWidth = 90;
inline const DWORD64 ShortcutTableDropDownWidth = 110; inline const DWORD64 ShortcutTableDropDownWidth = 160;
inline const DWORD64 ShortcutTableDropDownSpacing = 10; inline const DWORD64 ShortcutTableDropDownSpacing = 10;
inline const long ShortcutOriginColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing; inline const long ShortcutOriginColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing;
inline const long ShortcutTargetColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing + 15; inline const long ShortcutTargetColumnWidth = 3 * ShortcutTableDropDownWidth + 3 * ShortcutTableDropDownSpacing + 15;
// Drop down height used for both Edit Keyboard and Edit Shortcuts // Drop down height used for both Edit Keyboard and Edit Shortcuts
inline const DWORD64 TableDropDownHeight = 200; inline const DWORD64 TableDropDownHeight = 200;
inline const DWORD64 TableArrowColWidth = 230; inline const DWORD64 TableArrowColWidth = 130;
inline const DWORD64 TableRemoveColWidth = 20; inline const DWORD64 TableRemoveColWidth = 20;
inline const DWORD64 TableWarningColWidth = 20; inline const DWORD64 TableWarningColWidth = 20;
inline const DWORD64 TableTargetAppColWidth = ShortcutTableDropDownWidth + TableRemoveColWidth * 2; inline const DWORD64 TableTargetAppColWidth = ShortcutTableDropDownWidth + TableRemoveColWidth * 2;

View File

@ -51,8 +51,10 @@ std::vector<std::pair<DWORD, std::wstring>> KeyDropDownControl::GetKeyList(bool
void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisable) void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisable)
{ {
dropDown = ComboBox(); dropDown = ComboBox();
#ifndef USE_NEW_DROPDOWN_WARNING_TIP
warningFlyout = Flyout(); warningFlyout = Flyout();
warningMessage = TextBlock(); warningMessage = TextBlock();
#endif
if (!isShortcut) if (!isShortcut)
{ {
@ -77,6 +79,19 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
CheckAndUpdateKeyboardLayout(currentDropDown, isShortcut, renderDisable); CheckAndUpdateKeyboardLayout(currentDropDown, isShortcut, renderDisable);
}); });
#ifdef USE_NEW_DROPDOWN_WARNING_TIP
// Attach the tip to the drop down
warningTip.Target(dropDown.as<ComboBox>());
dropDown.as<ComboBox>().Loaded([&](winrt::Windows::Foundation::IInspectable const& sender, auto args) {
Media::VisualTreeHelper::GetChild(dropDown.as<ComboBox>(), 0).as<Grid>().Children().Append(warningTip);
});
// Tip properties
muxc::SymbolIconSource warningIcon;
warningIcon.Symbol(Symbol::Important);
warningTip.IconSource(warningIcon);
warningTip.IsLightDismissEnabled(true);
#else
// Attach flyout to the drop down // Attach flyout to the drop down
warningFlyout.as<Flyout>().Content(warningMessage.as<TextBlock>()); warningFlyout.as<Flyout>().Content(warningMessage.as<TextBlock>());
@ -86,6 +101,7 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut, bool renderDisabl
style.Setters().Append(Setter(Windows::UI::Xaml::Controls::Control::TabNavigationProperty(), winrt::box_value(Windows::UI::Xaml::Input::KeyboardNavigationMode::Cycle))); style.Setters().Append(Setter(Windows::UI::Xaml::Controls::Control::TabNavigationProperty(), winrt::box_value(Windows::UI::Xaml::Input::KeyboardNavigationMode::Cycle)));
warningFlyout.as<Flyout>().FlyoutPresenterStyle(style); warningFlyout.as<Flyout>().FlyoutPresenterStyle(style);
dropDown.as<ComboBox>().ContextFlyout().SetAttachedFlyout((FrameworkElement)dropDown.as<ComboBox>(), warningFlyout.as<Flyout>()); dropDown.as<ComboBox>().ContextFlyout().SetAttachedFlyout((FrameworkElement)dropDown.as<ComboBox>(), warningFlyout.as<Flyout>());
#endif
// To set the accessible name of the combo-box (by default index 1) // To set the accessible name of the combo-box (by default index 1)
SetAccessibleNameForComboBox(dropDown.as<ComboBox>(), 1); SetAccessibleNameForComboBox(dropDown.as<ComboBox>(), 1);
@ -376,6 +392,11 @@ void KeyDropDownControl::ValidateShortcutFromDropDownList(StackPanel table, Stac
void KeyDropDownControl::SetDropDownError(ComboBox currentDropDown, hstring message) void KeyDropDownControl::SetDropDownError(ComboBox currentDropDown, hstring message)
{ {
currentDropDown.SelectedIndex(-1); currentDropDown.SelectedIndex(-1);
#ifdef USE_NEW_DROPDOWN_WARNING_TIP
warningTip.Title(message);
warningTip.IsOpen(true);
#else
warningMessage.as<TextBlock>().Text(message); warningMessage.as<TextBlock>().Text(message);
try try
{ {
@ -386,6 +407,7 @@ void KeyDropDownControl::SetDropDownError(ComboBox currentDropDown, hstring mess
// If it's loading and some remaps are invalid from previous configs, avoid crashing when flyouts can't be showed yet. // If it's loading and some remaps are invalid from previous configs, avoid crashing when flyouts can't be showed yet.
Logger::error(L"Failed to show dropdown error flyout: {}", message); Logger::error(L"Failed to show dropdown error flyout: {}", message);
} }
#endif
} }
// Function to add a shortcut to the UI control as combo boxes // Function to add a shortcut to the UI control as combo boxes

View File

@ -2,6 +2,9 @@
#include <keyboardmanager/common/Shortcut.h> #include <keyboardmanager/common/Shortcut.h>
// Enables the WinUI teaching tip to show as the new warning flyout
#define USE_NEW_DROPDOWN_WARNING_TIP
namespace KBMEditor namespace KBMEditor
{ {
class KeyboardManagerState; class KeyboardManagerState;
@ -38,11 +41,16 @@ private:
// Stores the previous layout // Stores the previous layout
HKL previousLayout = 0; HKL previousLayout = 0;
#ifdef USE_NEW_DROPDOWN_WARNING_TIP
// Stores the teaching tip attached to the current drop down
muxc::TeachingTip warningTip;
#else
// Stores the flyout warning message // Stores the flyout warning message
winrt::Windows::Foundation::IInspectable warningMessage; winrt::Windows::Foundation::IInspectable warningMessage;
// Stores the flyout attached to the current drop down // Stores the flyout attached to the current drop down
winrt::Windows::Foundation::IInspectable warningFlyout; winrt::Windows::Foundation::IInspectable warningFlyout;
#endif
// Stores whether a key to shortcut warning has to be ignored // Stores whether a key to shortcut warning has to be ignored
bool ignoreKeyToShortcutWarning; bool ignoreKeyToShortcutWarning;

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props" Condition="Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" /> <Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion> <VCProjectVersion>16.0</VCProjectVersion>
@ -53,6 +55,7 @@
<ClInclude Include="trace.h" /> <ClInclude Include="trace.h" />
<ClInclude Include="UIHelpers.h" /> <ClInclude Include="UIHelpers.h" />
<ClInclude Include="XamlBridge.h" /> <ClInclude Include="XamlBridge.h" />
<ClInclude Include="XamlBridge2.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="BufferValidationHelpers.cpp" /> <ClCompile Include="BufferValidationHelpers.cpp" />
@ -74,6 +77,7 @@
<ClCompile Include="trace.cpp" /> <ClCompile Include="trace.cpp" />
<ClCompile Include="UIHelpers.cpp" /> <ClCompile Include="UIHelpers.cpp" />
<ClCompile Include="XamlBridge.cpp" /> <ClCompile Include="XamlBridge.cpp" />
<ClCompile Include="XamlBridge2.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />
@ -95,6 +99,9 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" /> <Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets')" />
</ImportGroup> </ImportGroup>
<Import Project="..\..\..\..\deps\spdlog.props" /> <Import Project="..\..\..\..\deps\spdlog.props" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
@ -103,6 +110,11 @@
</PropertyGroup> </PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" /> <Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" /> <Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.221104.6\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2088.41\build\native\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.UI.Xaml.2.8.2-prerelease.220830001\build\native\Microsoft.UI.Xaml.targets'))" />
</Target> </Target>
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild"> <Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory)\..\KeyboardManagerEditor\ resource.base.h resource.h KeyboardManagerEditor.base.rc KeyboardManagerEditor.rc" /> <Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory)\..\KeyboardManagerEditor\ resource.base.h resource.h KeyboardManagerEditor.base.rc KeyboardManagerEditor.rc" />

View File

@ -75,6 +75,9 @@
<ClInclude Include="EditorConstants.h"> <ClInclude Include="EditorConstants.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="XamlBridge2.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="pch.cpp"> <ClCompile Include="pch.cpp">
@ -128,6 +131,9 @@
<ClCompile Include="KeyDelay.cpp"> <ClCompile Include="KeyDelay.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="XamlBridge2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />

View File

@ -118,8 +118,15 @@ void KeyboardManagerState::AddKeyToLayout(const StackPanel& panel, const hstring
border.Padding({ 20, 10, 20, 10 }); border.Padding({ 20, 10, 20, 10 });
border.Margin({ 0, 0, 10, 0 }); border.Margin({ 0, 0, 10, 0 });
// Use the base low brush to be consistent with the theme
border.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>()); // Based on settings-ui\Settings.UI\SettingsXAML\Controls\KeyVisual\KeyVisual.xaml
border.Background(Application::Current().Resources().Lookup(box_value(L"ButtonBackground")).as<Media::Brush>());
border.BorderBrush(Application::Current().Resources().Lookup(box_value(L"ButtonBorderBrush")).as<Media::Brush>());
border.BorderThickness(unbox_value<Thickness>(Application::Current().Resources().Lookup(box_value(L"ButtonBorderThemeThickness"))));
border.CornerRadius(unbox_value<CornerRadius>(Application::Current().Resources().Lookup(box_value(L"ControlCornerRadius"))));
remapKey.Foreground(Application::Current().Resources().Lookup(box_value(L"ButtonForeground")).as<Media::Brush>());
remapKey.FontWeight(Text::FontWeights::SemiBold());
remapKey.FontSize(20); remapKey.FontSize(20);
border.HorizontalAlignment(HorizontalAlignment::Left); border.HorizontalAlignment(HorizontalAlignment::Left);
border.Child(remapKey); border.Child(remapKey);

View File

@ -90,13 +90,12 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
newrow.emplace_back(std::make_unique<ShortcutControl>(parent, row, 1, targetAppTextBox)); newrow.emplace_back(std::make_unique<ShortcutControl>(parent, row, 1, targetAppTextBox));
keyboardRemapControlObjects.push_back(std::move(newrow)); keyboardRemapControlObjects.push_back(std::move(newrow));
row.Padding({ 10, 10, 10, 10 }); row.Padding({ 10, 15, 10, 5 });
row.Margin({ 0, 0, 0, 2 });
row.Orientation(Orientation::Horizontal); row.Orientation(Orientation::Horizontal);
auto brush = Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundListLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>(); row.Background(Application::Current().Resources().Lookup(box_value(L"CardBackgroundFillColorDefaultBrush")).as<Media::Brush>());
if (keyboardRemapControlObjects.size() % 2) row.BorderBrush(Application::Current().Resources().Lookup(box_value(L"CardStrokeColorDefaultBrush")).as<Media::Brush>());
{ row.BorderThickness({ 0, 1, 0, 1 });
row.Background(brush);
}
// ShortcutControl for the original shortcut // ShortcutControl for the original shortcut
auto origin = keyboardRemapControlObjects.back()[0]->GetShortcutControl(); auto origin = keyboardRemapControlObjects.back()[0]->GetShortcutControl();
@ -104,14 +103,13 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
row.Children().Append(origin); row.Children().Append(origin);
// Arrow icon // Arrow icon
FontIcon arrowIcon; SymbolIcon arrowIcon(Symbol::Forward);
arrowIcon.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
arrowIcon.Glyph(L"\xE72A");
arrowIcon.VerticalAlignment(VerticalAlignment::Center); arrowIcon.VerticalAlignment(VerticalAlignment::Center);
arrowIcon.HorizontalAlignment(HorizontalAlignment::Center); arrowIcon.HorizontalAlignment(HorizontalAlignment::Center);
auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, EditorConstants::ShortcutArrowColumnWidth).as<StackPanel>(); auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, EditorConstants::ShortcutArrowColumnWidth).as<StackPanel>();
arrowIconContainer.Orientation(Orientation::Vertical); arrowIconContainer.Orientation(Orientation::Vertical);
arrowIconContainer.VerticalAlignment(VerticalAlignment::Center); arrowIconContainer.VerticalAlignment(VerticalAlignment::Center);
arrowIconContainer.Margin({ 0, 0, 0, 10 });
row.Children().Append(arrowIconContainer); row.Children().Append(arrowIconContainer);
// ShortcutControl for the new shortcut // ShortcutControl for the new shortcut
@ -122,6 +120,7 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
targetAppTextBox.Width(EditorConstants::ShortcutTableDropDownWidth); targetAppTextBox.Width(EditorConstants::ShortcutTableDropDownWidth);
targetAppTextBox.PlaceholderText(KeyboardManagerEditorStrings::DefaultAppName()); targetAppTextBox.PlaceholderText(KeyboardManagerEditorStrings::DefaultAppName());
targetAppTextBox.Text(targetAppName); targetAppTextBox.Text(targetAppName);
targetAppTextBox.Margin({ 0, 0, 0, 10 });
// GotFocus handler will be called whenever the user tabs into or clicks on the textbox // GotFocus handler will be called whenever the user tabs into or clicks on the textbox
targetAppTextBox.GotFocus([targetAppTextBox](auto const& sender, auto const& e) { targetAppTextBox.GotFocus([targetAppTextBox](auto const& sender, auto const& e) {
@ -194,13 +193,11 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
// Delete row button // Delete row button
Windows::UI::Xaml::Controls::Button deleteShortcut; Windows::UI::Xaml::Controls::Button deleteShortcut;
FontIcon deleteSymbol; deleteShortcut.Content(SymbolIcon(Symbol::Delete));
deleteSymbol.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
deleteSymbol.Glyph(L"\xE74D");
deleteShortcut.Content(deleteSymbol);
deleteShortcut.Background(Media::SolidColorBrush(Colors::Transparent())); deleteShortcut.Background(Media::SolidColorBrush(Colors::Transparent()));
deleteShortcut.HorizontalAlignment(HorizontalAlignment::Center); deleteShortcut.HorizontalAlignment(HorizontalAlignment::Center);
deleteShortcut.Click([&, parent, row, brush, deleteShortcut](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { deleteShortcut.Margin({ 0, 0, 0, 10 });
deleteShortcut.Click([&, parent, row, deleteShortcut](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
Button currentButton = sender.as<Button>(); Button currentButton = sender.as<Button>();
uint32_t rowIndex; uint32_t rowIndex;
// Get index of delete button // Get index of delete button
@ -216,7 +213,6 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<s
for (uint32_t i = rowIndex + 1; i < children.Size(); i++) for (uint32_t i = rowIndex + 1; i < children.Size(); i++)
{ {
StackPanel row = children.GetAt(i).as<StackPanel>(); StackPanel row = children.GetAt(i).as<StackPanel>();
row.Background(i % 2 ? brush : Media::SolidColorBrush(Colors::Transparent()));
StackPanel sourceCol = row.Children().GetAt(0).as<StackPanel>(); StackPanel sourceCol = row.Children().GetAt(0).as<StackPanel>();
StackPanel targetCol = row.Children().GetAt(2).as<StackPanel>(); StackPanel targetCol = row.Children().GetAt(2).as<StackPanel>();
TextBox targetApp = row.Children().GetAt(3).as<StackPanel>().Children().GetAt(0).as<StackPanel>().Children().GetAt(0).as<TextBox>(); TextBox targetApp = row.Children().GetAt(3).as<StackPanel>().Children().GetAt(0).as<StackPanel>().Children().GetAt(0).as<TextBox>();
@ -294,8 +290,6 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
// ContentDialog requires manually setting the XamlRoot (https://learn.microsoft.com/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands) // ContentDialog requires manually setting the XamlRoot (https://learn.microsoft.com/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands)
detectShortcutBox.XamlRoot(xamlRoot); detectShortcutBox.XamlRoot(xamlRoot);
detectShortcutBox.Title(box_value(GET_RESOURCE_STRING(IDS_TYPESHORTCUT_TITLE))); detectShortcutBox.Title(box_value(GET_RESOURCE_STRING(IDS_TYPESHORTCUT_TITLE)));
detectShortcutBox.IsPrimaryButtonEnabled(false);
detectShortcutBox.IsSecondaryButtonEnabled(false);
// Get the linked stack panel for the "Type shortcut" button that was clicked // Get the linked stack panel for the "Type shortcut" button that was clicked
VariableSizedWrapGrid linkedShortcutVariableSizedWrapGrid = UIHelpers::GetSiblingElement(sender).as<VariableSizedWrapGrid>(); VariableSizedWrapGrid linkedShortcutVariableSizedWrapGrid = UIHelpers::GetSiblingElement(sender).as<VariableSizedWrapGrid>();
@ -359,16 +353,13 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
onReleaseEnter(); onReleaseEnter();
}; };
TextBlock primaryButtonText;
primaryButtonText.Text(GET_RESOURCE_STRING(IDS_OK_BUTTON));
Button primaryButton;
primaryButton.HorizontalAlignment(HorizontalAlignment::Stretch);
primaryButton.Margin({ 2, 2, 2, 2 });
primaryButton.Content(primaryButtonText);
// OK button // OK button
primaryButton.Click([onAccept](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { detectShortcutBox.DefaultButton(ContentDialogButton::Primary);
detectShortcutBox.PrimaryButtonText(GET_RESOURCE_STRING(IDS_OK_BUTTON));
detectShortcutBox.PrimaryButtonClick([onAccept](winrt::Windows::Foundation::IInspectable const& sender, ContentDialogButtonClickEventArgs const& args) {
// Cancel default dialog events
args.Cancel(true);
onAccept(); onAccept();
}); });
@ -376,12 +367,10 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
keyboardManagerState.RegisterKeyDelay( keyboardManagerState.RegisterKeyDelay(
VK_RETURN, VK_RETURN,
selectDetectedShortcutAndResetKeys, selectDetectedShortcutAndResetKeys,
[primaryButton, onPressEnter, detectShortcutBox](DWORD) { [onPressEnter, detectShortcutBox](DWORD) {
detectShortcutBox.Dispatcher().RunAsync( detectShortcutBox.Dispatcher().RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal, Windows::UI::Core::CoreDispatcherPriority::Normal,
[primaryButton, onPressEnter] { [onPressEnter] {
// Use the base medium low brush to be consistent with the theme
primaryButton.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseMediumLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());
onPressEnter(); onPressEnter();
}); });
}, },
@ -393,9 +382,6 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
}); });
}); });
TextBlock cancelButtonText;
cancelButtonText.Text(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON));
auto onCancel = [&keyboardManagerState, auto onCancel = [&keyboardManagerState,
detectShortcutBox, detectShortcutBox,
unregisterKeys, unregisterKeys,
@ -418,12 +404,12 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
unregisterKeys(); unregisterKeys();
}; };
Button cancelButton;
cancelButton.HorizontalAlignment(HorizontalAlignment::Stretch);
cancelButton.Margin({ 2, 2, 2, 2 });
cancelButton.Content(cancelButtonText);
// Cancel button // Cancel button
cancelButton.Click([onCancel](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { detectShortcutBox.CloseButtonText(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON));
detectShortcutBox.CloseButtonClick([onCancel](winrt::Windows::Foundation::IInspectable const& sender, ContentDialogButtonClickEventArgs const& args) {
// Cancel default dialog events
args.Cancel(true);
onCancel(); onCancel();
}); });
@ -474,21 +460,6 @@ void ShortcutControl::CreateDetectShortcutWindow(winrt::Windows::Foundation::IIn
holdEnterInfo.Margin({ 0, 0, 0, 0 }); holdEnterInfo.Margin({ 0, 0, 0, 0 });
stackPanel.Children().Append(holdEnterInfo); stackPanel.Children().Append(holdEnterInfo);
ColumnDefinition primaryButtonColumn;
ColumnDefinition cancelButtonColumn;
Grid buttonPanel;
buttonPanel.Margin({ 0, 20, 0, 0 });
buttonPanel.HorizontalAlignment(HorizontalAlignment::Stretch);
buttonPanel.ColumnDefinitions().Append(primaryButtonColumn);
buttonPanel.ColumnDefinitions().Append(cancelButtonColumn);
buttonPanel.SetColumn(primaryButton, 0);
buttonPanel.SetColumn(cancelButton, 1);
buttonPanel.Children().Append(primaryButton);
buttonPanel.Children().Append(cancelButton);
stackPanel.Children().Append(buttonPanel);
try try
{ {
// If a layout update has been triggered by other methods (e.g.: adapting to zoom level), this may throw an exception. // If a layout update has been triggered by other methods (e.g.: adapting to zoom level), this may throw an exception.

View File

@ -84,33 +84,31 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
newrow.emplace_back(std::make_unique<SingleKeyRemapControl>(parent, row, 1)); newrow.emplace_back(std::make_unique<SingleKeyRemapControl>(parent, row, 1));
keyboardRemapControlObjects.push_back(std::move(newrow)); keyboardRemapControlObjects.push_back(std::move(newrow));
row.Padding({ 10, 10, 10, 10 }); row.Padding({ 10, 15, 10, 5 });
row.Margin({ 0, 0, 0, 2 });
row.Orientation(Orientation::Horizontal); row.Orientation(Orientation::Horizontal);
auto brush = Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundListLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>(); row.Background(Application::Current().Resources().Lookup(box_value(L"CardBackgroundFillColorDefaultBrush")).as<Media::Brush>());
if (keyboardRemapControlObjects.size() % 2) row.BorderBrush(Application::Current().Resources().Lookup(box_value(L"CardStrokeColorDefaultBrush")).as<Media::Brush>());
{ row.BorderThickness({ 0, 1, 0, 1 });
row.Background(brush);
}
// SingleKeyRemapControl for the original key. // SingleKeyRemapControl for the original key.
auto originalElement = keyboardRemapControlObjects.back()[0]->getSingleKeyRemapControl(); auto originalElement = keyboardRemapControlObjects.back()[0]->getSingleKeyRemapControl();
originalElement.Width(EditorConstants::RemapTableDropDownWidth + EditorConstants::ShortcutTableDropDownSpacing); originalElement.Width(EditorConstants::RemapTableDropDownWidth + EditorConstants::RemapTableDropDownSpacing);
row.Children().Append(originalElement); row.Children().Append(originalElement);
// Arrow icon // Arrow icon
FontIcon arrowIcon; SymbolIcon arrowIcon(Symbol::Forward);
arrowIcon.FontFamily(Media::FontFamily(L"Segoe MDL2 Assets"));
arrowIcon.Glyph(L"\xE72A");
arrowIcon.VerticalAlignment(VerticalAlignment::Center); arrowIcon.VerticalAlignment(VerticalAlignment::Center);
arrowIcon.HorizontalAlignment(HorizontalAlignment::Center); arrowIcon.HorizontalAlignment(HorizontalAlignment::Center);
auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, EditorConstants::TableArrowColWidth).as<StackPanel>(); auto arrowIconContainer = UIHelpers::GetWrapped(arrowIcon, EditorConstants::TableArrowColWidth).as<StackPanel>();
arrowIconContainer.Orientation(Orientation::Vertical); arrowIconContainer.Orientation(Orientation::Vertical);
arrowIconContainer.VerticalAlignment(VerticalAlignment::Center); arrowIconContainer.VerticalAlignment(VerticalAlignment::Center);
arrowIconContainer.Margin({ 0, 0, 0, 10 });
row.Children().Append(arrowIconContainer); row.Children().Append(arrowIconContainer);
// SingleKeyRemapControl for the new remap key // SingleKeyRemapControl for the new remap key
auto targetElement = keyboardRemapControlObjects.back()[1]->getSingleKeyRemapControl(); auto targetElement = keyboardRemapControlObjects.back()[1]->getSingleKeyRemapControl();
targetElement.Width(EditorConstants::ShortcutTargetColumnWidth); targetElement.Width(EditorConstants::RemapTargetColumnWidth);
row.Children().Append(targetElement); row.Children().Append(targetElement);
// Set the key text if the two keys are not null (i.e. default args) // Set the key text if the two keys are not null (i.e. default args)
@ -135,13 +133,11 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
// Delete row button // Delete row button
Windows::UI::Xaml::Controls::Button deleteRemapKeys; Windows::UI::Xaml::Controls::Button deleteRemapKeys;
FontIcon deleteSymbol; deleteRemapKeys.Content(SymbolIcon(Symbol::Delete));
deleteSymbol.FontFamily(Media::FontFamily(L"Segoe MDL2 Assets"));
deleteSymbol.Glyph(L"\xE74D");
deleteRemapKeys.Content(deleteSymbol);
deleteRemapKeys.Background(Media::SolidColorBrush(Colors::Transparent())); deleteRemapKeys.Background(Media::SolidColorBrush(Colors::Transparent()));
deleteRemapKeys.HorizontalAlignment(HorizontalAlignment::Center); deleteRemapKeys.HorizontalAlignment(HorizontalAlignment::Center);
deleteRemapKeys.Click([&, parent, row, brush, deleteRemapKeys](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { deleteRemapKeys.Margin({ 0, 0, 0, 10 });
deleteRemapKeys.Click([&, parent, row, deleteRemapKeys](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
uint32_t rowIndex; uint32_t rowIndex;
// Get index of delete button // Get index of delete button
UIElementCollection children = parent.Children(); UIElementCollection children = parent.Children();
@ -157,7 +153,6 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::ve
for (uint32_t i = rowIndex + 1; i < children.Size(); i++) for (uint32_t i = rowIndex + 1; i < children.Size(); i++)
{ {
StackPanel row = children.GetAt(i).as<StackPanel>(); StackPanel row = children.GetAt(i).as<StackPanel>();
row.Background(i % 2 ? brush : Media::SolidColorBrush(Colors::Transparent()));
StackPanel sourceCol = row.Children().GetAt(0).as<StackPanel>(); StackPanel sourceCol = row.Children().GetAt(0).as<StackPanel>();
StackPanel targetCol = row.Children().GetAt(2).as<StackPanel>(); StackPanel targetCol = row.Children().GetAt(2).as<StackPanel>();
Button delButton = row.Children().GetAt(3).as<Button>(); Button delButton = row.Children().GetAt(3).as<Button>();
@ -224,8 +219,6 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
// ContentDialog requires manually setting the XamlRoot (https://learn.microsoft.com/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands) // ContentDialog requires manually setting the XamlRoot (https://learn.microsoft.com/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands)
detectRemapKeyBox.XamlRoot(xamlRoot); detectRemapKeyBox.XamlRoot(xamlRoot);
detectRemapKeyBox.Title(box_value(GET_RESOURCE_STRING(IDS_TYPEKEY_TITLE))); detectRemapKeyBox.Title(box_value(GET_RESOURCE_STRING(IDS_TYPEKEY_TITLE)));
detectRemapKeyBox.IsPrimaryButtonEnabled(false);
detectRemapKeyBox.IsSecondaryButtonEnabled(false);
// Get the linked text block for the "Type Key" button that was clicked // Get the linked text block for the "Type Key" button that was clicked
ComboBox linkedRemapDropDown = UIHelpers::GetSiblingElement(sender).as<ComboBox>(); ComboBox linkedRemapDropDown = UIHelpers::GetSiblingElement(sender).as<ComboBox>();
@ -269,14 +262,13 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
onReleaseEnter(); onReleaseEnter();
}; };
TextBlock primaryButtonText; // OK button
primaryButtonText.Text(GET_RESOURCE_STRING(IDS_OK_BUTTON)); detectRemapKeyBox.DefaultButton(ContentDialogButton::Primary);
detectRemapKeyBox.PrimaryButtonText(GET_RESOURCE_STRING(IDS_OK_BUTTON));
detectRemapKeyBox.PrimaryButtonClick([onAccept](winrt::Windows::Foundation::IInspectable const& sender, ContentDialogButtonClickEventArgs const& args) {
// Cancel default dialog events
args.Cancel(true);
Button primaryButton;
primaryButton.HorizontalAlignment(HorizontalAlignment::Stretch);
primaryButton.Margin({ 2, 2, 2, 2 });
primaryButton.Content(primaryButtonText);
primaryButton.Click([onAccept](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
onAccept(); onAccept();
}); });
@ -284,12 +276,10 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
keyboardManagerState.RegisterKeyDelay( keyboardManagerState.RegisterKeyDelay(
VK_RETURN, VK_RETURN,
std::bind(&KBMEditor::KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1), std::bind(&KBMEditor::KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1),
[primaryButton, onPressEnter, detectRemapKeyBox](DWORD) { [onPressEnter, detectRemapKeyBox](DWORD) {
detectRemapKeyBox.Dispatcher().RunAsync( detectRemapKeyBox.Dispatcher().RunAsync(
Windows::UI::Core::CoreDispatcherPriority::Normal, Windows::UI::Core::CoreDispatcherPriority::Normal,
[primaryButton, onPressEnter] { [onPressEnter] {
// Use the base medium low brush to be consistent with the theme
primaryButton.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseMediumLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());
onPressEnter(); onPressEnter();
}); });
}, },
@ -301,9 +291,6 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
}); });
}); });
TextBlock cancelButtonText;
cancelButtonText.Text(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON));
auto onCancel = [&keyboardManagerState, auto onCancel = [&keyboardManagerState,
detectRemapKeyBox, detectRemapKeyBox,
unregisterKeys] { unregisterKeys] {
@ -317,13 +304,12 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
unregisterKeys(); unregisterKeys();
}; };
Button cancelButton;
cancelButton.HorizontalAlignment(HorizontalAlignment::Stretch);
cancelButton.Margin({ 2, 2, 2, 2 });
cancelButton.Content(cancelButtonText);
// Cancel button // Cancel button
cancelButton.Click([onCancel](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) { detectRemapKeyBox.CloseButtonText(GET_RESOURCE_STRING(IDS_CANCEL_BUTTON));
detectRemapKeyBox.CloseButtonClick([onCancel](winrt::Windows::Foundation::IInspectable const& sender, ContentDialogButtonClickEventArgs const& args) {
// Cancel default dialog events
args.Cancel(true);
onCancel(); onCancel();
}); });
@ -367,21 +353,6 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II
holdEnterInfo.Margin({ 0, 0, 0, 0 }); holdEnterInfo.Margin({ 0, 0, 0, 0 });
stackPanel.Children().Append(holdEnterInfo); stackPanel.Children().Append(holdEnterInfo);
ColumnDefinition primaryButtonColumn;
ColumnDefinition cancelButtonColumn;
Grid buttonPanel;
buttonPanel.Margin({ 0, 20, 0, 0 });
buttonPanel.HorizontalAlignment(HorizontalAlignment::Stretch);
buttonPanel.ColumnDefinitions().Append(primaryButtonColumn);
buttonPanel.ColumnDefinitions().Append(cancelButtonColumn);
buttonPanel.SetColumn(primaryButton, 0);
buttonPanel.SetColumn(cancelButton, 1);
buttonPanel.Children().Append(primaryButton);
buttonPanel.Children().Append(cancelButton);
stackPanel.Children().Append(buttonPanel);
try try
{ {
// If a layout update has been triggered by other methods (e.g.: adapting to zoom level), this may throw an exception. // If a layout update has been triggered by other methods (e.g.: adapting to zoom level), this may throw an exception.

View File

@ -1,15 +1,7 @@
#include "pch.h" #include "pch.h"
#include "Styles.h" #include "Styles.h"
#include <common/themes/windows_colors.h>
Style AccentButtonStyle() Style AccentButtonStyle()
{ {
Style style{ winrt::xaml_typename<Controls::Button>() }; return Application::Current().Resources().Lookup(box_value(L"AccentButtonStyle")).as<Style>();
style.Setters().Append(Setter{
Controls::Control::BackgroundProperty(),
winrt::Windows::UI::Xaml::Media::SolidColorBrush{ WindowsColors::get_accent_color() } });
style.Setters().Append(Setter{
Controls::Control::ForegroundProperty(),
winrt::Windows::UI::Xaml::Media::SolidColorBrush{ winrt::Windows::UI::Colors::White() } });
return style;
} }

View File

@ -0,0 +1,76 @@
#include "pch.h"
#include "XamlBridge2.h"
#include <CoreWindow.h> // ICoreWindowInterop
#include <winrt/Microsoft.Toolkit.Win32.UI.XamlHost.h>
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
namespace wac = Windows::ApplicationModel::Core;
// Stubbed implementation for frameworkView.Initialize()
struct XamlBridgeCoreAppViewImpl : implements<XamlBridgeCoreAppViewImpl, wac::ICoreApplicationView>
{
auto CoreWindow() { return Core::CoreWindow::GetForCurrentThread(); }
auto Activated(Windows::Foundation::TypedEventHandler<wac::CoreApplicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs> const&) { return event_token(); }
auto Activated(event_token const&) {}
auto IsMain() { return true; }
auto IsHosted() { return false; }
};
// Function to run the message loop for the xaml window
void XamlBridge2::MessageLoop()
{
Logger::trace("XamlBridge2::MessageLoop()");
frameworkView.Run();
Logger::trace("XamlBridge2::MessageLoop() stopped");
}
// Function to initialize the xaml bridge
HWND XamlBridge2::InitBridge()
{
Logger::trace("XamlBridge2::InitBridge()");
HRESULT hr = S_OK;
winrt::init_apartment(apartment_type::single_threaded);
auto windowsUIHandle = LoadLibrary(TEXT("Windows.UI.dll"));
auto pfnPrivateCreateCoreWindow = reinterpret_cast<fnPrivateCreateCoreWindow>(GetProcAddress(windowsUIHandle, MAKEINTRESOURCEA(1500)));
// Create the core window to host the XAML content
void* pCoreWindow;
hr = pfnPrivateCreateCoreWindow(IMMERSIVE_HOSTED, L"", 0, 0, 0, 0, 0, parentWindow, winrt::guid_of<Core::ICoreWindow>(), &pCoreWindow);
winrt::check_hresult(hr);
coreWindow = Core::CoreWindow(pCoreWindow, winrt::take_ownership_from_abi);
// Prep for the WinUI resources
auto app = Microsoft::Toolkit::Win32::UI::XamlHost::XamlApplication({ Microsoft::UI::Xaml::XamlTypeInfo::XamlControlsXamlMetaDataProvider() });
// Initialize the XAML framework
frameworkView.Initialize(*reinterpret_cast<wac::CoreApplicationView*>(&make<XamlBridgeCoreAppViewImpl>()));
frameworkView.SetWindow(coreWindow);
// Add the WinUI resources
app.Resources().MergedDictionaries().Append(muxc::XamlControlsResources());
auto coreWindowInterop = coreWindow.as<ICoreWindowInterop>();
hr = coreWindowInterop->get_WindowHandle(&coreWindowHwnd);
winrt::check_hresult(hr);
SetParent(coreWindowHwnd, parentWindow);
SetWindowLong(coreWindowHwnd, GWL_STYLE, WS_CHILD | WS_VISIBLE);
return coreWindowHwnd;
}
// Message Handler function for Xaml windows
LRESULT XamlBridge2::MessageHandler(UINT const message, WPARAM const wParam, LPARAM const lParam) noexcept
{
switch (message)
{
case WM_ACTIVATE:
case WM_MOVE:
SendMessage(coreWindowHwnd, message, wParam, lParam);
break;
}
return DefWindowProc(parentWindow, message, wParam, lParam);
}

View File

@ -0,0 +1,46 @@
#pragma once
// This class is used for handling XAML operations
class XamlBridge2
{
public:
// Function to run the message loop for the xaml window
void MessageLoop();
// Constructor
XamlBridge2(HWND parent) : parentWindow(parent) {}
// Function to initialize the xaml bridge
HWND InitBridge();
// Message Handler function for Xaml windows
LRESULT MessageHandler(UINT const message, WPARAM const wParam, LPARAM const lParam) noexcept;
private:
// Defines the window types for core windows
enum WINDOW_TYPE
{
IMMERSIVE_BODY = 0x0,
IMMERSIVE_DOCK = 0x1,
IMMERSIVE_HOSTED = 0x2,
IMMERSIVE_TEST = 0x3,
IMMERSIVE_BODY_ACTIVE = 0x4,
IMMERSIVE_DOCK_ACTIVE = 0x5,
NOT_IMMERSIVE = 0x6,
};
// Function signature for PrivateCreateCoreWindow
typedef HRESULT(CDECL* fnPrivateCreateCoreWindow)(WINDOW_TYPE WindowType, LPCWSTR pWindowTitle, INT X, INT Y, UINT uWidth, UINT uHeight, DWORD dwAttributes, HWND hOwnerWindow, REFIID riid, void** ppv);
// Stores the handle of the parent native window
HWND parentWindow = nullptr;
// Stores the core window for the UI thread
Core::CoreWindow coreWindow = nullptr;
// Stores the handle of the core window
HWND coreWindowHwnd = nullptr;
// Stores the xaml framework view for the UI thread
FrameworkView frameworkView;
};

View File

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.8.2-prerelease.220830001" targetFramework="native" />
<package id="Microsoft.Web.WebView2" version="1.0.2088.41" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.221104.6" targetFramework="native" /> <package id="Microsoft.Windows.CppWinRT" version="2.0.221104.6" targetFramework="native" />
</packages> </packages>

View File

@ -10,8 +10,10 @@
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h> #include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#include <winrt/Windows.Foundation.Collections.h> #include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.Metadata.h>
#include <winrt/Windows.UI.Core.h> #include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.UI.Text.h> #include <winrt/Windows.UI.Text.h>
#include <winrt/Windows.ApplicationModel.Core.h>
#pragma push_macro("GetCurrentTime") #pragma push_macro("GetCurrentTime")
#undef GetCurrentTime #undef GetCurrentTime
@ -21,6 +23,7 @@
#include <winrt/Windows.UI.Xaml.Hosting.h> #include <winrt/Windows.UI.Xaml.Hosting.h>
#include <winrt/Windows.UI.Xaml.Interop.h> #include <winrt/Windows.UI.Xaml.Interop.h>
#include <winrt/Windows.ui.xaml.media.h> #include <winrt/Windows.ui.xaml.media.h>
#include <winrt/Microsoft.UI.Xaml.Controls.h>
#pragma pop_macro("GetCurrentTime") #pragma pop_macro("GetCurrentTime")
#include <common/logger/logger.h> #include <common/logger/logger.h>
@ -38,3 +41,4 @@ using namespace Windows::UI::Xaml::Hosting;
using namespace Windows::Foundation::Numerics; using namespace Windows::Foundation::Numerics;
using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Controls;
namespace muxc = Microsoft::UI::Xaml::Controls;

View File

@ -71,77 +71,90 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.VSCodeHelper
foreach (var path in paths) foreach (var path in paths)
{ {
if (Directory.Exists(path)) if (!Directory.Exists(path))
{ {
var files = Directory.GetFiles(path) continue;
.Where(x => (x.Contains("code", StringComparison.OrdinalIgnoreCase) || x.Contains("codium", StringComparison.OrdinalIgnoreCase))
&& !x.EndsWith(".cmd", StringComparison.OrdinalIgnoreCase)).ToArray();
var iconPath = Path.GetDirectoryName(path);
if (files.Length > 0)
{
var file = files[0];
var version = string.Empty;
var instance = new VSCodeInstance
{
ExecutablePath = file,
};
if (file.EndsWith("code", StringComparison.OrdinalIgnoreCase))
{
version = "Code";
instance.VSCodeVersion = VSCodeVersion.Stable;
}
else if (file.EndsWith("code-insiders", StringComparison.OrdinalIgnoreCase))
{
version = "Code - Insiders";
instance.VSCodeVersion = VSCodeVersion.Insiders;
}
else if (file.EndsWith("code-exploration", StringComparison.OrdinalIgnoreCase))
{
version = "Code - Exploration";
instance.VSCodeVersion = VSCodeVersion.Exploration;
}
else if (file.EndsWith("codium", StringComparison.OrdinalIgnoreCase))
{
version = "VSCodium";
instance.VSCodeVersion = VSCodeVersion.Stable;
}
else if (file.EndsWith("codium-insiders", StringComparison.OrdinalIgnoreCase))
{
version = "VSCodium - Insiders";
instance.VSCodeVersion = VSCodeVersion.Insiders;
}
if (version != string.Empty)
{
var portableData = Path.Join(iconPath, "data");
instance.AppData = Directory.Exists(portableData) ? Path.Join(portableData, "user-data") : Path.Combine(_userAppDataPath, version);
var vsCodeIconPath = Path.Join(iconPath, $"{version}.exe");
var vsCodeIcon = Icon.ExtractAssociatedIcon(vsCodeIconPath);
if (vsCodeIcon != null)
{
using var vsCodeIconBitmap = vsCodeIcon.ToBitmap();
// workspace
using var folderIcon = (Bitmap)Image.FromFile(Path.Join(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Images//folder.png"));
using var bitmapFolderIcon = BitmapOverlayToCenter(folderIcon, vsCodeIconBitmap);
instance.WorkspaceIconBitMap = Bitmap2BitmapImage(bitmapFolderIcon);
// remote
using var monitorIcon = (Bitmap)Image.FromFile(Path.Join(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Images//monitor.png"));
using var bitmapMonitorIcon = BitmapOverlayToCenter(monitorIcon, vsCodeIconBitmap);
instance.RemoteIconBitMap = Bitmap2BitmapImage(bitmapMonitorIcon);
}
Instances.Add(instance);
}
}
} }
var files = Directory.GetFiles(path)
.Where(x => (x.Contains("code", StringComparison.OrdinalIgnoreCase) || x.Contains("codium", StringComparison.OrdinalIgnoreCase))
&& !x.EndsWith(".cmd", StringComparison.OrdinalIgnoreCase)).ToArray();
// Remove the trailing backslash to always get the correct path
var iconPath = Path.GetDirectoryName(path.TrimEnd('\\'));
if (files.Length == 0)
{
continue;
}
var file = files[0];
var version = string.Empty;
var instance = new VSCodeInstance
{
ExecutablePath = file,
};
if (file.EndsWith("code", StringComparison.OrdinalIgnoreCase))
{
version = "Code";
instance.VSCodeVersion = VSCodeVersion.Stable;
}
else if (file.EndsWith("code-insiders", StringComparison.OrdinalIgnoreCase))
{
version = "Code - Insiders";
instance.VSCodeVersion = VSCodeVersion.Insiders;
}
else if (file.EndsWith("code-exploration", StringComparison.OrdinalIgnoreCase))
{
version = "Code - Exploration";
instance.VSCodeVersion = VSCodeVersion.Exploration;
}
else if (file.EndsWith("codium", StringComparison.OrdinalIgnoreCase))
{
version = "VSCodium";
instance.VSCodeVersion = VSCodeVersion.Stable;
}
else if (file.EndsWith("codium-insiders", StringComparison.OrdinalIgnoreCase))
{
version = "VSCodium - Insiders";
instance.VSCodeVersion = VSCodeVersion.Insiders;
}
if (string.IsNullOrEmpty(version))
{
continue;
}
var portableData = Path.Join(iconPath, "data");
instance.AppData = Directory.Exists(portableData) ? Path.Join(portableData, "user-data") : Path.Combine(_userAppDataPath, version);
var vsCodeIconPath = Path.Join(iconPath, $"{version}.exe");
if (!File.Exists(vsCodeIconPath))
{
continue;
}
var vsCodeIcon = Icon.ExtractAssociatedIcon(vsCodeIconPath);
if (vsCodeIcon == null)
{
continue;
}
using var vsCodeIconBitmap = vsCodeIcon.ToBitmap();
// Workspace
using var folderIcon = (Bitmap)Image.FromFile(Path.Join(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Images//folder.png"));
using var bitmapFolderIcon = BitmapOverlayToCenter(folderIcon, vsCodeIconBitmap);
instance.WorkspaceIconBitMap = Bitmap2BitmapImage(bitmapFolderIcon);
// Remote
using var monitorIcon = (Bitmap)Image.FromFile(Path.Join(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Images//monitor.png"));
using var bitmapMonitorIcon = BitmapOverlayToCenter(monitorIcon, vsCodeIconBitmap);
instance.RemoteIconBitMap = Bitmap2BitmapImage(bitmapMonitorIcon);
Instances.Add(instance);
} }
} }
} }

View File

@ -5,14 +5,15 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Globalization; using System.Globalization;
using System.IO;
using System.IO.Abstractions; using System.IO.Abstractions;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using ManagedCommon; using ManagedCommon;
using Wox.Infrastructure.UserSettings;
using Wox.Plugin; using Wox.Plugin;
using Wox.Plugin.Logger; using Wox.Plugin.Logger;
@ -43,20 +44,46 @@ namespace Wox.Infrastructure.Image
".ico", ".ico",
}; };
// Checks whether it is a valid PNG by checking the 8 bytes at the beginning of the file.
public static bool IsValidPngSignature(string filePath)
{
byte[] pngSignature = { 137, 80, 78, 71, 13, 10, 26, 10 };
byte[] buffer = new byte[8];
using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
return fs.Read(buffer, 0, buffer.Length) == buffer.Length && pngSignature.SequenceEqual(buffer);
}
public static void Initialize(Theme theme) public static void Initialize(Theme theme)
{ {
_hashGenerator = new ImageHashGenerator(); _hashGenerator = new ImageHashGenerator();
foreach (var icon in new[] { Constant.ErrorIcon, Constant.LightThemedErrorIcon }) foreach (var icon in new[] { Constant.ErrorIcon, Constant.LightThemedErrorIcon })
{ {
BitmapImage bmi = new BitmapImage(); var uri = new Uri(icon);
bmi.BeginInit();
bmi.UriSource = new Uri(icon); try
bmi.CacheOption = BitmapCacheOption.OnLoad; {
bmi.EndInit(); if (File.Exists(uri.LocalPath) && IsValidPngSignature(uri.LocalPath))
ImageSource img = bmi; {
img.Freeze(); BitmapImage bmi = new BitmapImage();
ImageCache[icon] = img; bmi.BeginInit();
bmi.UriSource = uri;
bmi.CacheOption = BitmapCacheOption.OnLoad;
bmi.EndInit();
ImageSource img = bmi;
img.Freeze();
ImageCache[icon] = img;
}
else
{
Log.Error($"Image file '{icon}' is not a valid PNG.", MethodBase.GetCurrentMethod().DeclaringType);
}
}
catch (COMException comEx)
{
Log.Exception($"COMException was thrown in {uri.LocalPath} file.", comEx, MethodBase.GetCurrentMethod().DeclaringType);
}
} }
UpdateIconPath(theme); UpdateIconPath(theme);

View File

@ -40,6 +40,9 @@
Source="{x:Bind VideoPreviewer.Preview, Mode=OneWay}" Source="{x:Bind VideoPreviewer.Preview, Mode=OneWay}"
ToolTipService.ToolTip="{x:Bind ImageInfoTooltip, Mode=OneWay}" ToolTipService.ToolTip="{x:Bind ImageInfoTooltip, Mode=OneWay}"
Visibility="{x:Bind IsPreviewVisible(VideoPreviewer, Previewer.State), Mode=OneWay}"> Visibility="{x:Bind IsPreviewVisible(VideoPreviewer, Previewer.State), Mode=OneWay}">
<MediaPlayerElement.KeyboardAccelerators>
<KeyboardAccelerator Key="Space" Invoked="KeyboardAccelerator_Space_Invoked" />
</MediaPlayerElement.KeyboardAccelerators>
<MediaPlayerElement.TransportControls> <MediaPlayerElement.TransportControls>
<MediaTransportControls <MediaTransportControls
x:Name="mediaTransport" x:Name="mediaTransport"

View File

@ -299,6 +299,28 @@ namespace Peek.FilePreviewer
} }
} }
private void KeyboardAccelerator_Space_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
var mediaPlayer = VideoPreview.MediaPlayer;
if (mediaPlayer.Source == null || !mediaPlayer.CanPause)
{
return;
}
if (mediaPlayer.CurrentState == Windows.Media.Playback.MediaPlayerState.Playing)
{
mediaPlayer.Pause();
}
else
{
mediaPlayer.Play();
}
// Prevent the keyboard accelerator to be called twice
args.Handled = true;
}
private async Task UpdateImageTooltipAsync(CancellationToken cancellationToken) private async Task UpdateImageTooltipAsync(CancellationToken cancellationToken)
{ {
if (Item == null) if (Item == null)

View File

@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System;
using interop;
using ManagedCommon; using ManagedCommon;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@ -11,6 +12,7 @@ using Microsoft.UI.Xaml;
using Peek.Common; using Peek.Common;
using Peek.FilePreviewer; using Peek.FilePreviewer;
using Peek.FilePreviewer.Models; using Peek.FilePreviewer.Models;
using Peek.UI.Native;
using Peek.UI.Telemetry.Events; using Peek.UI.Telemetry.Events;
using Peek.UI.Views; using Peek.UI.Views;
@ -28,7 +30,7 @@ namespace Peek.UI
get; get;
} }
private Window? Window { get; set; } private MainWindow? Window { get; set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="App"/> class. /// Initializes a new instance of the <see cref="App"/> class.
@ -96,12 +98,32 @@ namespace Peek.UI
} }
} }
Window = new MainWindow(); NativeEventWaiter.WaitForEventLoop(Constants.ShowPeekEvent(), OnPeekHotkey);
} }
private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
{ {
PowerToysTelemetry.Log.WriteEvent(new ErrorEvent() { HResult = (Common.Models.HResult)e.Exception.HResult, Failure = ErrorEvent.FailureType.AppCrash }); PowerToysTelemetry.Log.WriteEvent(new ErrorEvent() { HResult = (Common.Models.HResult)e.Exception.HResult, Failure = ErrorEvent.FailureType.AppCrash });
} }
/// <summary>
/// Handle Peek hotkey
/// </summary>
private void OnPeekHotkey()
{
// Need to read the foreground HWND before activating Peek to avoid focus stealing
// Foreground HWND must always be Explorer or Desktop
var foregroundWindowHandle = Windows.Win32.PInvoke.GetForegroundWindow();
bool firstActivation = false;
if (Window == null)
{
firstActivation = true;
Window = new MainWindow();
}
Window.Toggle(firstActivation, foregroundWindowHandle);
}
} }
} }

View File

@ -1,9 +1,8 @@
// Copyright (c) Microsoft Corporation // Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System;
using interop;
using ManagedCommon; using ManagedCommon;
using Microsoft.PowerToys.Telemetry; using Microsoft.PowerToys.Telemetry;
using Microsoft.UI; using Microsoft.UI;
@ -15,7 +14,6 @@ using Peek.Common.Extensions;
using Peek.FilePreviewer.Models; using Peek.FilePreviewer.Models;
using Peek.UI.Extensions; using Peek.UI.Extensions;
using Peek.UI.Helpers; using Peek.UI.Helpers;
using Peek.UI.Native;
using Peek.UI.Telemetry.Events; using Peek.UI.Telemetry.Events;
using Windows.Foundation; using Windows.Foundation;
using WinUIEx; using WinUIEx;
@ -30,7 +28,6 @@ namespace Peek.UI
public MainWindowViewModel ViewModel { get; } public MainWindowViewModel ViewModel { get; }
private ThemeListener? themeListener; private ThemeListener? themeListener;
private bool activated;
public MainWindow() public MainWindow()
{ {
@ -49,13 +46,40 @@ namespace Peek.UI
ViewModel = Application.Current.GetService<MainWindowViewModel>(); ViewModel = Application.Current.GetService<MainWindowViewModel>();
NativeEventWaiter.WaitForEventLoop(Constants.ShowPeekEvent(), OnPeekHotkey);
TitleBarControl.SetTitleBarToWindow(this); TitleBarControl.SetTitleBarToWindow(this);
AppWindow.Closing += AppWindow_Closing; AppWindow.Closing += AppWindow_Closing;
} }
/// <summary>
/// Toggling the window visibility and querying files when necessary.
/// </summary>
public void Toggle(bool firstActivation, Windows.Win32.Foundation.HWND foregroundWindowHandle)
{
if (firstActivation)
{
Activate();
Initialize(foregroundWindowHandle);
return;
}
if (AppWindow.IsVisible)
{
if (IsNewSingleSelectedItem(foregroundWindowHandle))
{
Initialize(foregroundWindowHandle);
}
else
{
Uninitialize();
}
}
else
{
Initialize(foregroundWindowHandle);
}
}
private void HandleThemeChange() private void HandleThemeChange()
{ {
AppWindow appWindow = this.AppWindow; AppWindow appWindow = this.AppWindow;
@ -82,41 +106,6 @@ namespace Peek.UI
} }
} }
/// <summary>
/// Handle Peek hotkey, by toggling the window visibility and querying files when necessary.
/// </summary>
private void OnPeekHotkey()
{
// Need to read the foreground HWND before activating Peek to avoid focus stealing
// Foreground HWND must always be Explorer or Desktop
var foregroundWindowHandle = Windows.Win32.PInvoke.GetForegroundWindow();
// First Peek activation
if (!activated)
{
Activate();
Initialize(foregroundWindowHandle);
activated = true;
return;
}
if (AppWindow.IsVisible)
{
if (IsNewSingleSelectedItem(foregroundWindowHandle))
{
Initialize(foregroundWindowHandle);
}
else
{
Uninitialize();
}
}
else
{
Initialize(foregroundWindowHandle);
}
}
private void PreviousNavigationInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) private void PreviousNavigationInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{ {
ViewModel.AttemptPreviousNavigation(); ViewModel.AttemptPreviousNavigation();

View File

@ -14,10 +14,12 @@ namespace PowerAccent.Core
CUR, CUR,
CY, CY,
CZ, CZ,
DK,
GA, GA,
GD, GD,
DE, DE,
EST, EST,
FI,
FR, FR,
HR, HR,
HE, HE,
@ -52,10 +54,12 @@ namespace PowerAccent.Core
Language.CUR => GetDefaultLetterKeyCUR(letter), // Currency Language.CUR => GetDefaultLetterKeyCUR(letter), // Currency
Language.CY => GetDefaultLetterKeyCY(letter), // Welsh Language.CY => GetDefaultLetterKeyCY(letter), // Welsh
Language.CZ => GetDefaultLetterKeyCZ(letter), // Czech Language.CZ => GetDefaultLetterKeyCZ(letter), // Czech
Language.DK => GetDefaultLetterKeyDK(letter), // Danish
Language.GA => GetDefaultLetterKeyGA(letter), // Gaeilge (Irish) Language.GA => GetDefaultLetterKeyGA(letter), // Gaeilge (Irish)
Language.GD => GetDefaultLetterKeyGD(letter), // Gàidhlig (Scottish Gaelic) Language.GD => GetDefaultLetterKeyGD(letter), // Gàidhlig (Scottish Gaelic)
Language.DE => GetDefaultLetterKeyDE(letter), // German Language.DE => GetDefaultLetterKeyDE(letter), // German
Language.EST => GetDefaultLetterKeyEST(letter), // Estonian Language.EST => GetDefaultLetterKeyEST(letter), // Estonian
Language.FI => GetDefaultLetterKeyFI(letter), // Finnish
Language.FR => GetDefaultLetterKeyFR(letter), // French Language.FR => GetDefaultLetterKeyFR(letter), // French
Language.HR => GetDefaultLetterKeyHR(letter), // Croatian Language.HR => GetDefaultLetterKeyHR(letter), // Croatian
Language.HE => GetDefaultLetterKeyHE(letter), // Hebrew Language.HE => GetDefaultLetterKeyHE(letter), // Hebrew
@ -93,10 +97,12 @@ namespace PowerAccent.Core
.Union(GetDefaultLetterKeyCUR(letter)) .Union(GetDefaultLetterKeyCUR(letter))
.Union(GetDefaultLetterKeyCY(letter)) .Union(GetDefaultLetterKeyCY(letter))
.Union(GetDefaultLetterKeyCZ(letter)) .Union(GetDefaultLetterKeyCZ(letter))
.Union(GetDefaultLetterKeyDK(letter))
.Union(GetDefaultLetterKeyGA(letter)) .Union(GetDefaultLetterKeyGA(letter))
.Union(GetDefaultLetterKeyGD(letter)) .Union(GetDefaultLetterKeyGD(letter))
.Union(GetDefaultLetterKeyDE(letter)) .Union(GetDefaultLetterKeyDE(letter))
.Union(GetDefaultLetterKeyEST(letter)) .Union(GetDefaultLetterKeyEST(letter))
.Union(GetDefaultLetterKeyFI(letter))
.Union(GetDefaultLetterKeyFR(letter)) .Union(GetDefaultLetterKeyFR(letter))
.Union(GetDefaultLetterKeyHR(letter)) .Union(GetDefaultLetterKeyHR(letter))
.Union(GetDefaultLetterKeyHE(letter)) .Union(GetDefaultLetterKeyHE(letter))
@ -131,6 +137,13 @@ namespace PowerAccent.Core
{ {
return letter switch return letter switch
{ {
LetterKey.VK_0 => new[] { "↉" },
LetterKey.VK_1 => new[] { "½", "⅓", "¼", "⅕", "⅙", "⅐", "⅛", "⅑", "⅒" },
LetterKey.VK_2 => new[] { "⅔", "⅖" },
LetterKey.VK_3 => new[] { "¾", "⅗", "⅜" },
LetterKey.VK_4 => new[] { "⅘" },
LetterKey.VK_5 => new[] { "⅚", "⅝" },
LetterKey.VK_7 => new[] { "⅞" },
LetterKey.VK_A => new[] { "α", "ά", "ȧ" }, LetterKey.VK_A => new[] { "α", "ά", "ȧ" },
LetterKey.VK_B => new[] { "ḃ", "β" }, LetterKey.VK_B => new[] { "ḃ", "β" },
LetterKey.VK_C => new[] { "ċ", "χ", "°C", "©", "" }, LetterKey.VK_C => new[] { "ċ", "χ", "°C", "©", "" },
@ -155,7 +168,7 @@ namespace PowerAccent.Core
LetterKey.VK_V => new[] { "V̇" }, LetterKey.VK_V => new[] { "V̇" },
LetterKey.VK_W => new[] { "ẇ" }, LetterKey.VK_W => new[] { "ẇ" },
LetterKey.VK_X => new[] { "ẋ", "ξ", "×" }, LetterKey.VK_X => new[] { "ẋ", "ξ", "×" },
LetterKey.VK_Y => new[] { "ẏ" }, LetterKey.VK_Y => new[] { "ẏ", "ꝡ" },
LetterKey.VK_Z => new[] { "ʒ", "ǯ", "ζ", "" }, LetterKey.VK_Z => new[] { "ʒ", "ǯ", "ζ", "" },
LetterKey.VK_COMMA => new[] { "∙", "₋", "⁻", "" }, // is in VK_MINUS for other languages, but not VK_COMMA, so we add it here. LetterKey.VK_COMMA => new[] { "∙", "₋", "⁻", "" }, // is in VK_MINUS for other languages, but not VK_COMMA, so we add it here.
LetterKey.VK_PERIOD => new[] { "\u0300", "\u0301", "\u0302", "\u0303", "\u0304", "\u0308", "\u030C" }, LetterKey.VK_PERIOD => new[] { "\u0300", "\u0301", "\u0302", "\u0303", "\u0304", "\u0308", "\u030C" },
@ -200,6 +213,7 @@ namespace PowerAccent.Core
{ {
LetterKey.VK_C => new[] { "ć", "č" }, LetterKey.VK_C => new[] { "ć", "č" },
LetterKey.VK_D => new[] { "đ" }, LetterKey.VK_D => new[] { "đ" },
LetterKey.VK_E => new[] { "€" },
LetterKey.VK_S => new[] { "š" }, LetterKey.VK_S => new[] { "š" },
LetterKey.VK_Z => new[] { "ž" }, LetterKey.VK_Z => new[] { "ž" },
_ => Array.Empty<string>(), _ => Array.Empty<string>(),
@ -221,6 +235,18 @@ namespace PowerAccent.Core
}; };
} }
// Finnish
private static string[] GetDefaultLetterKeyFI(LetterKey letter)
{
return letter switch
{
LetterKey.VK_A => new[] { "ä", "å" },
LetterKey.VK_E => new[] { "€" },
LetterKey.VK_O => new[] { "ö" },
_ => Array.Empty<string>(),
};
}
// French // French
private static string[] GetDefaultLetterKeyFR(LetterKey letter) private static string[] GetDefaultLetterKeyFR(LetterKey letter)
{ {
@ -438,7 +464,7 @@ namespace PowerAccent.Core
return letter switch return letter switch
{ {
LetterKey.VK_A => new[] { "á" }, LetterKey.VK_A => new[] { "á" },
LetterKey.VK_E => new[] { "é" }, LetterKey.VK_E => new[] { "é", "€" },
LetterKey.VK_I => new[] { "í" }, LetterKey.VK_I => new[] { "í" },
LetterKey.VK_O => new[] { "ó" }, LetterKey.VK_O => new[] { "ó" },
LetterKey.VK_U => new[] { "ú" }, LetterKey.VK_U => new[] { "ú" },
@ -455,6 +481,7 @@ namespace PowerAccent.Core
LetterKey.VK_E => new[] { "è" }, LetterKey.VK_E => new[] { "è" },
LetterKey.VK_I => new[] { "ì" }, LetterKey.VK_I => new[] { "ì" },
LetterKey.VK_O => new[] { "ò" }, LetterKey.VK_O => new[] { "ò" },
LetterKey.VK_P => new[] { "£" },
LetterKey.VK_U => new[] { "ù" }, LetterKey.VK_U => new[] { "ù" },
_ => Array.Empty<string>(), _ => Array.Empty<string>(),
}; };
@ -588,6 +615,7 @@ namespace PowerAccent.Core
LetterKey.VK_E => new[] { "ê" }, LetterKey.VK_E => new[] { "ê" },
LetterKey.VK_I => new[] { "î" }, LetterKey.VK_I => new[] { "î" },
LetterKey.VK_O => new[] { "ô" }, LetterKey.VK_O => new[] { "ô" },
LetterKey.VK_P => new[] { "£" },
LetterKey.VK_U => new[] { "û" }, LetterKey.VK_U => new[] { "û" },
LetterKey.VK_Y => new[] { "ŷ" }, LetterKey.VK_Y => new[] { "ŷ" },
LetterKey.VK_W => new[] { "ŵ" }, LetterKey.VK_W => new[] { "ŵ" },
@ -644,6 +672,18 @@ namespace PowerAccent.Core
}; };
} }
// Danish
private static string[] GetDefaultLetterKeyDK(LetterKey letter)
{
return letter switch
{
LetterKey.VK_A => new[] { "å", "æ" },
LetterKey.VK_E => new[] { "€" },
LetterKey.VK_O => new[] { "ø" },
_ => Array.Empty<string>(),
};
}
// Lithuanian // Lithuanian
private static string[] GetDefaultLetterKeyLT(LetterKey letter) private static string[] GetDefaultLetterKeyLT(LetterKey letter)
{ {

View File

@ -0,0 +1,133 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
namespace Microsoft.PowerToys.Settings.UI.Helpers
{
internal sealed class ModuleHelper
{
public static string GetModuleLabelResourceName(ModuleType moduleType)
{
switch (moduleType)
{
case ModuleType.PowerAccent: return "QuickAccent/ModuleTitle";
case ModuleType.PowerOCR: return "TextExtractor/ModuleTitle";
case ModuleType.FindMyMouse:
case ModuleType.MouseHighlighter:
case ModuleType.MouseJump:
case ModuleType.MousePointerCrosshairs: return $"MouseUtils_{moduleType}/Header";
default: return $"{moduleType}/ModuleTitle";
}
}
public static string GetModuleTypeFluentIconName(ModuleType moduleType)
{
switch (moduleType)
{
case ModuleType.MousePointerCrosshairs: return "ms-appx:///Assets/Settings/FluentIcons/FluentIconsMouseCrosshairs.png";
case ModuleType.MeasureTool: return "ms-appx:///Assets/Settings/FluentIcons/FluentIconsScreenRuler.png";
case ModuleType.PowerLauncher: return $"ms-appx:///Assets/Settings/FluentIcons/FluentIconsPowerToysRun.png";
default: return $"ms-appx:///Assets/Settings/FluentIcons/FluentIcons{moduleType}.png";
}
}
public static bool GetIsModuleEnabled(Library.GeneralSettings generalSettingsConfig, ModuleType moduleType)
{
switch (moduleType)
{
case ModuleType.AlwaysOnTop: return generalSettingsConfig.Enabled.AlwaysOnTop;
case ModuleType.Awake: return generalSettingsConfig.Enabled.Awake;
case ModuleType.ColorPicker: return generalSettingsConfig.Enabled.ColorPicker;
case ModuleType.CropAndLock: return generalSettingsConfig.Enabled.CropAndLock;
case ModuleType.EnvironmentVariables: return generalSettingsConfig.Enabled.EnvironmentVariables;
case ModuleType.FancyZones: return generalSettingsConfig.Enabled.FancyZones;
case ModuleType.FileLocksmith: return generalSettingsConfig.Enabled.FileLocksmith;
case ModuleType.FindMyMouse: return generalSettingsConfig.Enabled.FindMyMouse;
case ModuleType.Hosts: return generalSettingsConfig.Enabled.Hosts;
case ModuleType.ImageResizer: return generalSettingsConfig.Enabled.ImageResizer;
case ModuleType.KeyboardManager: return generalSettingsConfig.Enabled.KeyboardManager;
case ModuleType.MouseHighlighter: return generalSettingsConfig.Enabled.MouseHighlighter;
case ModuleType.MouseJump: return generalSettingsConfig.Enabled.MouseJump;
case ModuleType.MousePointerCrosshairs: return generalSettingsConfig.Enabled.MousePointerCrosshairs;
case ModuleType.MouseWithoutBorders: return generalSettingsConfig.Enabled.MouseWithoutBorders;
case ModuleType.PastePlain: return generalSettingsConfig.Enabled.PastePlain;
case ModuleType.Peek: return generalSettingsConfig.Enabled.Peek;
case ModuleType.PowerRename: return generalSettingsConfig.Enabled.PowerRename;
case ModuleType.PowerLauncher: return generalSettingsConfig.Enabled.PowerLauncher;
case ModuleType.PowerAccent: return generalSettingsConfig.Enabled.PowerAccent;
case ModuleType.RegistryPreview: return generalSettingsConfig.Enabled.RegistryPreview;
case ModuleType.MeasureTool: return generalSettingsConfig.Enabled.MeasureTool;
case ModuleType.ShortcutGuide: return generalSettingsConfig.Enabled.ShortcutGuide;
case ModuleType.PowerOCR: return generalSettingsConfig.Enabled.PowerOCR;
default: return false;
}
}
internal static void SetIsModuleEnabled(GeneralSettings generalSettingsConfig, ModuleType moduleType, bool isEnabled)
{
switch (moduleType)
{
case ModuleType.AlwaysOnTop: generalSettingsConfig.Enabled.AlwaysOnTop = isEnabled; break;
case ModuleType.Awake: generalSettingsConfig.Enabled.Awake = isEnabled; break;
case ModuleType.ColorPicker: generalSettingsConfig.Enabled.ColorPicker = isEnabled; break;
case ModuleType.CropAndLock: generalSettingsConfig.Enabled.CropAndLock = isEnabled; break;
case ModuleType.EnvironmentVariables: generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break;
case ModuleType.FancyZones: generalSettingsConfig.Enabled.FancyZones = isEnabled; break;
case ModuleType.FileLocksmith: generalSettingsConfig.Enabled.FileLocksmith = isEnabled; break;
case ModuleType.FindMyMouse: generalSettingsConfig.Enabled.FindMyMouse = isEnabled; break;
case ModuleType.Hosts: generalSettingsConfig.Enabled.Hosts = isEnabled; break;
case ModuleType.ImageResizer: generalSettingsConfig.Enabled.ImageResizer = isEnabled; break;
case ModuleType.KeyboardManager: generalSettingsConfig.Enabled.KeyboardManager = isEnabled; break;
case ModuleType.MouseHighlighter: generalSettingsConfig.Enabled.MouseHighlighter = isEnabled; break;
case ModuleType.MouseJump: generalSettingsConfig.Enabled.MouseJump = isEnabled; break;
case ModuleType.MousePointerCrosshairs: generalSettingsConfig.Enabled.MousePointerCrosshairs = isEnabled; break;
case ModuleType.MouseWithoutBorders: generalSettingsConfig.Enabled.MouseWithoutBorders = isEnabled; break;
case ModuleType.PastePlain: generalSettingsConfig.Enabled.PastePlain = isEnabled; break;
case ModuleType.Peek: generalSettingsConfig.Enabled.Peek = isEnabled; break;
case ModuleType.PowerRename: generalSettingsConfig.Enabled.PowerRename = isEnabled; break;
case ModuleType.PowerLauncher: generalSettingsConfig.Enabled.PowerLauncher = isEnabled; break;
case ModuleType.PowerAccent: generalSettingsConfig.Enabled.PowerAccent = isEnabled; break;
case ModuleType.RegistryPreview: generalSettingsConfig.Enabled.RegistryPreview = isEnabled; break;
case ModuleType.MeasureTool: generalSettingsConfig.Enabled.MeasureTool = isEnabled; break;
case ModuleType.ShortcutGuide: generalSettingsConfig.Enabled.ShortcutGuide = isEnabled; break;
case ModuleType.PowerOCR: generalSettingsConfig.Enabled.PowerOCR = isEnabled; break;
}
}
public static GpoRuleConfigured GetModuleGpoConfiguration(ModuleType moduleType)
{
switch (moduleType)
{
case ModuleType.AlwaysOnTop: return GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue();
case ModuleType.Awake: return GPOWrapper.GetConfiguredAwakeEnabledValue();
case ModuleType.ColorPicker: return GPOWrapper.GetConfiguredColorPickerEnabledValue();
case ModuleType.CropAndLock: return GPOWrapper.GetConfiguredCropAndLockEnabledValue();
case ModuleType.EnvironmentVariables: return GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue();
case ModuleType.FancyZones: return GPOWrapper.GetConfiguredFancyZonesEnabledValue();
case ModuleType.FileLocksmith: return GPOWrapper.GetConfiguredFileLocksmithEnabledValue();
case ModuleType.FindMyMouse: return GPOWrapper.GetConfiguredFindMyMouseEnabledValue();
case ModuleType.Hosts: return GPOWrapper.GetConfiguredHostsFileEditorEnabledValue();
case ModuleType.ImageResizer: return GPOWrapper.GetConfiguredImageResizerEnabledValue();
case ModuleType.KeyboardManager: return GPOWrapper.GetConfiguredKeyboardManagerEnabledValue();
case ModuleType.MouseHighlighter: return GPOWrapper.GetConfiguredMouseHighlighterEnabledValue();
case ModuleType.MouseJump: return GPOWrapper.GetConfiguredMouseJumpEnabledValue();
case ModuleType.MousePointerCrosshairs: return GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue();
case ModuleType.MouseWithoutBorders: return GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue();
case ModuleType.PastePlain: return GPOWrapper.GetConfiguredPastePlainEnabledValue();
case ModuleType.Peek: return GPOWrapper.GetConfiguredPeekEnabledValue();
case ModuleType.PowerRename: return GPOWrapper.GetConfiguredPowerRenameEnabledValue();
case ModuleType.PowerLauncher: return GPOWrapper.GetConfiguredPowerLauncherEnabledValue();
case ModuleType.PowerAccent: return GPOWrapper.GetConfiguredQuickAccentEnabledValue();
case ModuleType.RegistryPreview: return GPOWrapper.GetConfiguredRegistryPreviewEnabledValue();
case ModuleType.MeasureTool: return GPOWrapper.GetConfiguredScreenRulerEnabledValue();
case ModuleType.ShortcutGuide: return GPOWrapper.GetConfiguredShortcutGuideEnabledValue();
case ModuleType.PowerOCR: return GPOWrapper.GetConfiguredTextExtractorEnabledValue();
default: return GpoRuleConfigured.Unavailable;
}
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Threading; using System.Threading;
using global::Windows.System; using global::Windows.System;
using interop; using interop;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Controls; using Microsoft.PowerToys.Settings.UI.Controls;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events; using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
@ -37,16 +38,16 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
// Closing manually the flyout to workaround focus gain problems // Closing manually the flyout to workaround focus gain problems
App.GetFlyoutWindow()?.Hide(); App.GetFlyoutWindow()?.Hide();
switch ((string)selectedModuleBtn.Tag) switch ((ModuleType)selectedModuleBtn.Tag)
{ {
case "ColorPicker": // Launch ColorPicker case ModuleType.ColorPicker: // Launch ColorPicker
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowColorPickerSharedEvent())) using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowColorPickerSharedEvent()))
{ {
eventHandle.Set(); eventHandle.Set();
} }
break; break;
case "EnvironmentVariables": // Launch Environment Variables case ModuleType.EnvironmentVariables: // Launch Environment Variables
{ {
bool launchAdmin = SettingsRepository<EnvironmentVariablesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator; bool launchAdmin = SettingsRepository<EnvironmentVariablesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator;
string eventName = !App.IsElevated && launchAdmin string eventName = !App.IsElevated && launchAdmin
@ -61,7 +62,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
break; break;
case "FancyZones": // Launch FancyZones Editor case ModuleType.FancyZones: // Launch FancyZones Editor
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.FZEToggleEvent())) using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.FZEToggleEvent()))
{ {
eventHandle.Set(); eventHandle.Set();
@ -69,7 +70,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
break; break;
case "Hosts": // Launch Hosts case ModuleType.Hosts: // Launch Hosts
{ {
bool launchAdmin = SettingsRepository<HostsSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator; bool launchAdmin = SettingsRepository<HostsSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator;
string eventName = !App.IsElevated && launchAdmin string eventName = !App.IsElevated && launchAdmin
@ -84,14 +85,14 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
break; break;
case "RegistryPreview": // Launch Registry Preview case ModuleType.RegistryPreview: // Launch Registry Preview
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.RegistryPreviewTriggerEvent())) using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.RegistryPreviewTriggerEvent()))
{ {
eventHandle.Set(); eventHandle.Set();
} }
break; break;
case "MeasureTool": // Launch Screen Ruler case ModuleType.MeasureTool: // Launch Screen Ruler
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.MeasureToolTriggerEvent())) using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.MeasureToolTriggerEvent()))
{ {
eventHandle.Set(); eventHandle.Set();
@ -99,7 +100,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
break; break;
case "PowerLauncher": // Launch Run case ModuleType.PowerLauncher: // Launch Run
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.PowerLauncherSharedEvent())) using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.PowerLauncherSharedEvent()))
{ {
eventHandle.Set(); eventHandle.Set();
@ -107,7 +108,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
break; break;
case "PowerOCR": // Launch Text Extractor case ModuleType.PowerOCR: // Launch Text Extractor
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowPowerOCRSharedEvent())) using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowPowerOCRSharedEvent()))
{ {
eventHandle.Set(); eventHandle.Set();
@ -115,7 +116,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
break; break;
case "ShortcutGuide": // Launch Shortcut Guide case ModuleType.ShortcutGuide: // Launch Shortcut Guide
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShortcutGuideTriggerEvent())) using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShortcutGuideTriggerEvent()))
{ {
eventHandle.Set(); eventHandle.Set();
@ -130,7 +131,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
if (moduleRun) if (moduleRun)
{ {
PowerToysTelemetry.Log.WriteEvent(new TrayFlyoutModuleRunEvent() { ModuleName = (string)selectedModuleBtn.Tag }); PowerToysTelemetry.Log.WriteEvent(new TrayFlyoutModuleRunEvent() { ModuleName = ((ModuleType)selectedModuleBtn.Tag).ToString() });
} }
} }

View File

@ -81,92 +81,15 @@ namespace Microsoft.PowerToys.Settings.UI
}); });
// open main window // open main window
ShellPage.SetUpdatingGeneralSettingsCallback((string module, bool isEnabled) => ShellPage.SetUpdatingGeneralSettingsCallback((ModuleType moduleType, bool isEnabled) =>
{ {
SettingsRepository<GeneralSettings> repository = SettingsRepository<GeneralSettings>.GetInstance(new SettingsUtils()); SettingsRepository<GeneralSettings> repository = SettingsRepository<GeneralSettings>.GetInstance(new SettingsUtils());
GeneralSettings generalSettingsConfig = repository.SettingsConfig; GeneralSettings generalSettingsConfig = repository.SettingsConfig;
bool needToUpdate = false; bool needToUpdate = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType) != isEnabled;
switch (module)
{
case "AlwaysOnTop":
needToUpdate = generalSettingsConfig.Enabled.AlwaysOnTop != isEnabled;
generalSettingsConfig.Enabled.AlwaysOnTop = isEnabled; break;
case "Awake":
needToUpdate = generalSettingsConfig.Enabled.Awake != isEnabled;
generalSettingsConfig.Enabled.Awake = isEnabled; break;
case "ColorPicker":
needToUpdate = generalSettingsConfig.Enabled.ColorPicker != isEnabled;
generalSettingsConfig.Enabled.ColorPicker = isEnabled; break;
case "CropAndLock":
needToUpdate = generalSettingsConfig.Enabled.CropAndLock != isEnabled;
generalSettingsConfig.Enabled.CropAndLock = isEnabled; break;
case "EnvironmentVariables":
needToUpdate = generalSettingsConfig.Enabled.EnvironmentVariables != isEnabled;
generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break;
case "FancyZones":
needToUpdate = generalSettingsConfig.Enabled.FancyZones != isEnabled;
generalSettingsConfig.Enabled.FancyZones = isEnabled; break;
case "FileLocksmith":
needToUpdate = generalSettingsConfig.Enabled.FileLocksmith != isEnabled;
generalSettingsConfig.Enabled.FileLocksmith = isEnabled; break;
case "FindMyMouse":
needToUpdate = generalSettingsConfig.Enabled.FindMyMouse != isEnabled;
generalSettingsConfig.Enabled.FindMyMouse = isEnabled; break;
case "Hosts":
needToUpdate = generalSettingsConfig.Enabled.Hosts != isEnabled;
generalSettingsConfig.Enabled.Hosts = isEnabled; break;
case "ImageResizer":
needToUpdate = generalSettingsConfig.Enabled.ImageResizer != isEnabled;
generalSettingsConfig.Enabled.ImageResizer = isEnabled; break;
case "KeyboardManager":
needToUpdate = generalSettingsConfig.Enabled.KeyboardManager != isEnabled;
generalSettingsConfig.Enabled.KeyboardManager = isEnabled; break;
case "MouseHighlighter":
needToUpdate = generalSettingsConfig.Enabled.MouseHighlighter != isEnabled;
generalSettingsConfig.Enabled.MouseHighlighter = isEnabled; break;
case "MouseJump":
needToUpdate = generalSettingsConfig.Enabled.MouseJump != isEnabled;
generalSettingsConfig.Enabled.MouseJump = isEnabled; break;
case "MousePointerCrosshairs":
needToUpdate = generalSettingsConfig.Enabled.MousePointerCrosshairs != isEnabled;
generalSettingsConfig.Enabled.MousePointerCrosshairs = isEnabled; break;
case "MouseWithoutBorders":
needToUpdate = generalSettingsConfig.Enabled.MouseWithoutBorders != isEnabled;
generalSettingsConfig.Enabled.MouseWithoutBorders = isEnabled; break;
case "PastePlain":
needToUpdate = generalSettingsConfig.Enabled.PastePlain != isEnabled;
generalSettingsConfig.Enabled.PastePlain = isEnabled; break;
case "Peek":
needToUpdate = generalSettingsConfig.Enabled.Peek != isEnabled;
generalSettingsConfig.Enabled.Peek = isEnabled; break;
case "PowerRename":
needToUpdate = generalSettingsConfig.Enabled.PowerRename != isEnabled;
generalSettingsConfig.Enabled.PowerRename = isEnabled; break;
case "PowerLauncher":
needToUpdate = generalSettingsConfig.Enabled.PowerLauncher != isEnabled;
generalSettingsConfig.Enabled.PowerLauncher = isEnabled; break;
case "PowerAccent":
needToUpdate = generalSettingsConfig.Enabled.PowerAccent != isEnabled;
generalSettingsConfig.Enabled.PowerAccent = isEnabled; break;
case "RegistryPreview":
needToUpdate = generalSettingsConfig.Enabled.RegistryPreview != isEnabled;
generalSettingsConfig.Enabled.RegistryPreview = isEnabled; break;
case "MeasureTool":
needToUpdate = generalSettingsConfig.Enabled.MeasureTool != isEnabled;
generalSettingsConfig.Enabled.MeasureTool = isEnabled; break;
case "ShortcutGuide":
needToUpdate = generalSettingsConfig.Enabled.ShortcutGuide != isEnabled;
generalSettingsConfig.Enabled.ShortcutGuide = isEnabled; break;
case "PowerOCR":
needToUpdate = generalSettingsConfig.Enabled.PowerOCR != isEnabled;
generalSettingsConfig.Enabled.PowerOCR = isEnabled; break;
case "VideoConference":
needToUpdate = generalSettingsConfig.Enabled.VideoConference != isEnabled;
generalSettingsConfig.Enabled.VideoConference = isEnabled; break;
}
if (needToUpdate) if (needToUpdate)
{ {
ModuleHelper.SetIsModuleEnabled(generalSettingsConfig, moduleType, isEnabled);
var outgoing = new OutGoingGeneralSettings(generalSettingsConfig); var outgoing = new OutGoingGeneralSettings(generalSettingsConfig);
this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
{ {

View File

@ -49,10 +49,5 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{ {
ViewModel.SWVersionButtonClicked(); ViewModel.SWVersionButtonClicked();
} }
private void SettingsButtonClicked(object sender, RoutedEventArgs e)
{
ViewModel.SettingsButtonClicked(sender);
}
} }
} }

View File

@ -49,10 +49,12 @@
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Currency" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Currency" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Croatian" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Croatian" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Czech" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Czech" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Danish" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Gaeilge" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Gaeilge" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Gaidhlig" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Gaidhlig" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Dutch" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Dutch" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Estonian" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Estonian" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Finnish" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_French" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_French" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_German" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_German" />
<ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Hebrew" /> <ComboBoxItem x:Uid="QuickAccent_SelectedLanguage_Hebrew" />

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Services; using Microsoft.PowerToys.Settings.UI.Services;
using Microsoft.PowerToys.Settings.UI.ViewModels; using Microsoft.PowerToys.Settings.UI.ViewModels;
@ -34,7 +35,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
/// <summary> /// <summary>
/// Declaration for the updating the general settings callback function. /// Declaration for the updating the general settings callback function.
/// </summary> /// </summary>
public delegate bool UpdatingGeneralSettingsCallback(string module, bool isEnabled); public delegate bool UpdatingGeneralSettingsCallback(ModuleType moduleType, bool isEnabled);
/// <summary> /// <summary>
/// Declaration for the opening oobe window callback function. /// Declaration for the opening oobe window callback function.

View File

@ -3316,6 +3316,9 @@ Activate by holding the key for the character you want to add an accent to, then
<data name="QuickAccent_SelectedLanguage_Czech.Content" xml:space="preserve"> <data name="QuickAccent_SelectedLanguage_Czech.Content" xml:space="preserve">
<value>Czech</value> <value>Czech</value>
</data> </data>
<data name="QuickAccent_SelectedLanguage_Danish.Content" xml:space="preserve">
<value>Danish</value>
</data>
<data name="QuickAccent_SelectedLanguage_Gaeilge.Content" xml:space="preserve"> <data name="QuickAccent_SelectedLanguage_Gaeilge.Content" xml:space="preserve">
<value>Gaeilge</value> <value>Gaeilge</value>
<comment>Gaelic language spoken in Ireland</comment> <comment>Gaelic language spoken in Ireland</comment>
@ -3333,6 +3336,9 @@ Activate by holding the key for the character you want to add an accent to, then
<data name="QuickAccent_SelectedLanguage_French.Content" xml:space="preserve"> <data name="QuickAccent_SelectedLanguage_French.Content" xml:space="preserve">
<value>French</value> <value>French</value>
</data> </data>
<data name="QuickAccent_SelectedLanguage_Finnish.Content" xml:space="preserve">
<value>Finnish</value>
</data>
<data name="QuickAccent_SelectedLanguage_Estonian.Content" xml:space="preserve"> <data name="QuickAccent_SelectedLanguage_Estonian.Content" xml:space="preserve">
<value>Estonian</value> <value>Estonian</value>
</data> </data>

View File

@ -6,6 +6,7 @@ using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using ManagedCommon;
using Microsoft.UI; using Microsoft.UI;
using Windows.UI; using Windows.UI;
@ -22,7 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
public string ToolTip { get; set; } public string ToolTip { get; set; }
public string Tag { get; set; } public ModuleType Tag { get; set; }
public Color AccentColor { get; set; } = Colors.Transparent; public Color AccentColor { get; set; } = Colors.Transparent;

View File

@ -9,6 +9,8 @@ using System.IO.Abstractions;
using System.Linq; using System.Linq;
using System.Windows.Threading; using System.Windows.Threading;
using global::PowerToys.GPOWrapper; using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
@ -23,7 +25,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
public class DashboardViewModel : Observable public class DashboardViewModel : Observable
{ {
private const string JsonFileType = ".json"; private const string JsonFileType = ".json";
private readonly IFileSystemWatcher _watcher; private IFileSystemWatcher _watcher;
private DashboardModuleKBMItem _kbmItem; private DashboardModuleKBMItem _kbmItem;
private Dispatcher dispatcher; private Dispatcher dispatcher;
@ -53,325 +55,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_allModules = new List<DashboardListItem>(); _allModules = new List<DashboardListItem>();
GpoRuleConfigured gpo; foreach (ModuleType moduleType in Enum.GetValues(typeof(ModuleType)))
gpo = GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue();
_allModules.Add(new DashboardListItem()
{ {
Tag = "AlwaysOnTop", AddDashboardListItem(moduleType);
Label = resourceLoader.GetString("AlwaysOnTop/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.AlwaysOnTop),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsAlwaysOnTop.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 74, 196, 242), // #4ac4f2
DashboardModuleItems = GetModuleItemsAlwaysOnTop(),
});
gpo = GPOWrapper.GetConfiguredAwakeEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "Awake",
Label = resourceLoader.GetString("Awake/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.Awake),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsAwake.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 40, 177, 233), // #28b1e9
DashboardModuleItems = GetModuleItemsAwake(),
});
gpo = GPOWrapper.GetConfiguredColorPickerEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "ColorPicker",
Label = resourceLoader.GetString("ColorPicker/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.ColorPicker),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsColorPicker.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 7, 129, 211), // #0781d3
DashboardModuleItems = GetModuleItemsColorPicker(),
});
gpo = GPOWrapper.GetConfiguredCropAndLockEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "CropAndLock",
Label = resourceLoader.GetString("CropAndLock/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.CropAndLock),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsCropAndLock.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 32, 166, 228), // #20a6e4
DashboardModuleItems = GetModuleItemsCropAndLock(),
});
gpo = GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "EnvironmentVariables",
Label = resourceLoader.GetString("EnvironmentVariables/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.EnvironmentVariables),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsEnvironmentVariables.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 16, 132, 208), // #1084d0
DashboardModuleItems = GetModuleItemsEnvironmentVariables(),
});
gpo = GPOWrapper.GetConfiguredFancyZonesEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "FancyZones",
Label = resourceLoader.GetString("FancyZones/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.FancyZones),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsFancyZones.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 65, 209, 247), // #41d1f7
DashboardModuleItems = GetModuleItemsFancyZones(),
});
gpo = GPOWrapper.GetConfiguredFileLocksmithEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "FileLocksmith",
Label = resourceLoader.GetString("FileLocksmith/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.FileLocksmith),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsFileLocksmith.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 245, 161, 20), // #f5a114
DashboardModuleItems = GetModuleItemsFileLocksmith(),
});
gpo = GPOWrapper.GetConfiguredFindMyMouseEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "FindMyMouse",
Label = resourceLoader.GetString("MouseUtils_FindMyMouse/Header"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.FindMyMouse),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsFindMyMouse.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 104, 109, 112), // #686d70
DashboardModuleItems = GetModuleItemsFindMyMouse(),
});
gpo = GPOWrapper.GetConfiguredHostsFileEditorEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "Hosts",
Label = resourceLoader.GetString("Hosts/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.Hosts),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsHosts.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 16, 132, 208), // #1084d0
DashboardModuleItems = GetModuleItemsHosts(),
});
gpo = GPOWrapper.GetConfiguredImageResizerEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "ImageResizer",
Label = resourceLoader.GetString("ImageResizer/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.ImageResizer),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsImageResizer.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 85, 207, 248), // #55cff8
DashboardModuleItems = GetModuleItemsImageResizer(),
});
gpo = GPOWrapper.GetConfiguredKeyboardManagerEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "KeyboardManager",
Label = resourceLoader.GetString("KeyboardManager/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.KeyboardManager),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsKeyboardManager.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 224, 231, 238), // #e0e7ee
DashboardModuleItems = GetModuleItemsKeyboardManager(),
});
if (gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.KeyboardManager))
{
KeyboardManagerSettings kbmSettings = GetKBMSettings();
_watcher = Library.Utilities.Helper.GetFileWatcher(KeyboardManagerSettings.ModuleName, kbmSettings.Properties.ActiveConfiguration.Value + JsonFileType, () => LoadKBMSettingsFromJson());
} }
gpo = GPOWrapper.GetConfiguredMouseHighlighterEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "MouseHighlighter",
Label = resourceLoader.GetString("MouseUtils_MouseHighlighter/Header"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.MouseHighlighter),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsMouseHighlighter.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 17, 126, 199), // #117ec7
DashboardModuleItems = GetModuleItemsMouseHighlighter(),
});
gpo = GPOWrapper.GetConfiguredMouseJumpEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "MouseJump",
Label = resourceLoader.GetString("MouseUtils_MouseJump/Header"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.MouseJump),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsMouseJump.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 240, 240, 239), // #f0f0ef
DashboardModuleItems = GetModuleItemsMouseJump(),
});
gpo = GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "MousePointerCrosshairs",
Label = resourceLoader.GetString("MouseUtils_MousePointerCrosshairs/Header"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.MousePointerCrosshairs),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsMouseCrosshairs.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 25, 115, 182), // #1973b6
DashboardModuleItems = GetModuleItemsMouseCrosshairs(),
});
gpo = GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "MouseWithoutBorders",
Label = resourceLoader.GetString("MouseWithoutBorders/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.MouseWithoutBorders),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsMouseWithoutBorders.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 31, 164, 227), // #1fa4e3
DashboardModuleItems = GetModuleItemsMouseWithoutBorders(),
});
gpo = GPOWrapper.GetConfiguredPastePlainEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "PastePlain",
Label = resourceLoader.GetString("PastePlain/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.PastePlain),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsPastePlain.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 243, 156, 16), // #f39c10
DashboardModuleItems = GetModuleItemsPastePlain(),
});
gpo = GPOWrapper.GetConfiguredPeekEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "Peek",
Label = resourceLoader.GetString("Peek/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.Peek),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsPeek.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 255, 214, 103), // #ffd667
DashboardModuleItems = GetModuleItemsPeek(),
});
gpo = GPOWrapper.GetConfiguredPowerRenameEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "PowerRename",
Label = resourceLoader.GetString("PowerRename/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.PowerRename),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsPowerRename.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 43, 186, 243), // #2bbaf3
DashboardModuleItems = GetModuleItemsPowerRename(),
});
gpo = GPOWrapper.GetConfiguredPowerLauncherEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "PowerLauncher",
Label = resourceLoader.GetString("PowerLauncher/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.PowerLauncher),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsPowerToysRun.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 51, 191, 240), // #33bff0
DashboardModuleItems = GetModuleItemsRun(),
});
gpo = GPOWrapper.GetConfiguredQuickAccentEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "PowerAccent",
Label = resourceLoader.GetString("QuickAccent/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.PowerAccent),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsPowerAccent.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 84, 89, 92), // #54595c
DashboardModuleItems = GetModuleItemsPowerAccent(),
});
gpo = GPOWrapper.GetConfiguredRegistryPreviewEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "RegistryPreview",
Label = resourceLoader.GetString("RegistryPreview/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.RegistryPreview),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsRegistryPreview.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 17, 80, 138), // #11508a
DashboardModuleItems = GetModuleItemsRegistryPreview(),
});
gpo = GPOWrapper.GetConfiguredScreenRulerEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "MeasureTool",
Label = resourceLoader.GetString("MeasureTool/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.MeasureTool),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsScreenRuler.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 135, 144, 153), // #879099
DashboardModuleItems = GetModuleItemsScreenRuler(),
});
gpo = GPOWrapper.GetConfiguredShortcutGuideEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "ShortcutGuide",
Label = resourceLoader.GetString("ShortcutGuide/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.ShortcutGuide),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsShortcutGuide.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 193, 202, 209), // #c1cad1
DashboardModuleItems = GetModuleItemsShortcutGuide(),
});
gpo = GPOWrapper.GetConfiguredTextExtractorEnabledValue();
_allModules.Add(new DashboardListItem()
{
Tag = "PowerOCR",
Label = resourceLoader.GetString("TextExtractor/ModuleTitle"),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && generalSettingsConfig.Enabled.PowerOCR),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsPowerOCR.png",
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = Color.FromArgb(255, 24, 153, 224), // #1899e0
DashboardModuleItems = GetModuleItemsPowerOCR(),
});
ActiveModules = new ObservableCollection<DashboardListItem>(_allModules.Where(x => x.IsEnabled)); ActiveModules = new ObservableCollection<DashboardListItem>(_allModules.Where(x => x.IsEnabled));
DisabledModules = new ObservableCollection<DashboardListItem>(_allModules.Where(x => !x.IsEnabled)); DisabledModules = new ObservableCollection<DashboardListItem>(_allModules.Where(x => !x.IsEnabled));
@ -379,6 +67,59 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
UpdateAvailable = updatingSettingsConfig != null && (updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToInstall || updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToDownload); UpdateAvailable = updatingSettingsConfig != null && (updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToInstall || updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToDownload);
} }
private void AddDashboardListItem(ModuleType moduleType)
{
GpoRuleConfigured gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
_allModules.Add(new DashboardListItem()
{
Tag = moduleType,
Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType)),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
EnabledChangedCallback = EnabledChangedOnUI,
AccentColor = GetModuleAccentColor(moduleType),
DashboardModuleItems = GetModuleItems(moduleType),
});
if (moduleType == ModuleType.KeyboardManager && gpo != GpoRuleConfigured.Disabled)
{
KeyboardManagerSettings kbmSettings = GetKBMSettings();
_watcher = Library.Utilities.Helper.GetFileWatcher(KeyboardManagerSettings.ModuleName, kbmSettings.Properties.ActiveConfiguration.Value + JsonFileType, () => LoadKBMSettingsFromJson());
}
}
private Color GetModuleAccentColor(ModuleType moduleType)
{
return moduleType switch
{
ModuleType.AlwaysOnTop => Color.FromArgb(255, 74, 196, 242), // #4ac4f2
ModuleType.Awake => Color.FromArgb(255, 40, 177, 233), // #28b1e9
ModuleType.ColorPicker => Color.FromArgb(255, 7, 129, 211), // #0781d3
ModuleType.CropAndLock => Color.FromArgb(255, 32, 166, 228), // #20a6e4
ModuleType.EnvironmentVariables => Color.FromArgb(255, 16, 132, 208), // #1084d0
ModuleType.FancyZones => Color.FromArgb(255, 65, 209, 247), // #41d1f7
ModuleType.FileLocksmith => Color.FromArgb(255, 245, 161, 20), // #f5a114
ModuleType.FindMyMouse => Color.FromArgb(255, 104, 109, 112), // #686d70
ModuleType.Hosts => Color.FromArgb(255, 16, 132, 208), // #1084d0
ModuleType.ImageResizer => Color.FromArgb(255, 85, 207, 248), // #55cff8
ModuleType.KeyboardManager => Color.FromArgb(255, 224, 231, 238), // #e0e7ee
ModuleType.MouseHighlighter => Color.FromArgb(255, 17, 126, 199), // #117ec7
ModuleType.MouseJump => Color.FromArgb(255, 240, 240, 239), // #f0f0ef
ModuleType.MousePointerCrosshairs => Color.FromArgb(255, 25, 115, 182), // #1973b6
ModuleType.MouseWithoutBorders => Color.FromArgb(255, 31, 164, 227), // #1fa4e3
ModuleType.PastePlain => Color.FromArgb(255, 243, 156, 16), // #f39c10
ModuleType.Peek => Color.FromArgb(255, 255, 214, 103), // #ffd667
ModuleType.PowerRename => Color.FromArgb(255, 43, 186, 243), // #2bbaf3
ModuleType.PowerLauncher => Color.FromArgb(255, 51, 191, 240), // #33bff0
ModuleType.PowerAccent => Color.FromArgb(255, 84, 89, 92), // #54595c
ModuleType.RegistryPreview => Color.FromArgb(255, 17, 80, 138), // #11508a
ModuleType.MeasureTool => Color.FromArgb(255, 135, 144, 153), // #879099
ModuleType.ShortcutGuide => Color.FromArgb(255, 193, 202, 209), // #c1cad1
ModuleType.PowerOCR => Color.FromArgb(255, 24, 153, 224), // #1899e0
_ => Color.FromArgb(255, 255, 255, 255), // never called, all values listed above
};
}
private void LoadKBMSettingsFromJson() private void LoadKBMSettingsFromJson()
{ {
KeyboardManagerProfile kbmProfile = GetKBMProfile(); KeyboardManagerProfile kbmProfile = GetKBMProfile();
@ -408,52 +149,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
return moduleSettingsRepository.SettingsConfig; return moduleSettingsRepository.SettingsConfig;
} }
internal void SettingsButtonClicked(object sender)
{
Button button = sender as Button;
if (button == null)
{
return;
}
string tag = button.Tag as string;
if (tag == null)
{
return;
}
Type type = null;
switch (tag)
{
case "AlwaysOnTop": type = typeof(AlwaysOnTopPage); break;
case "Awake": type = typeof(AwakePage); break;
case "ColorPicker": type = typeof(ColorPickerPage); break;
case "CropAndLock": type = typeof(CropAndLockPage); break;
case "FancyZones": type = typeof(FancyZonesPage); break;
case "FileLocksmith": type = typeof(FileLocksmithPage); break;
case "FindMyMouse": type = typeof(MouseUtilsPage); break;
case "Hosts": type = typeof(HostsPage); break;
case "ImageResizer": type = typeof(ImageResizerPage); break;
case "KeyboardManager": type = typeof(KeyboardManagerPage); break;
case "MouseHighlighter": type = typeof(MouseUtilsPage); break;
case "MouseJump": type = typeof(MouseUtilsPage); break;
case "MousePointerCrosshairs": type = typeof(MouseUtilsPage); break;
case "MouseWithoutBorders": type = typeof(MouseWithoutBordersPage); break;
case "PastePlain": type = typeof(PastePlainPage); break;
case "Peek": type = typeof(PeekPage); break;
case "PowerRename": type = typeof(PowerRenamePage); break;
case "PowerLauncher": type = typeof(PowerLauncherPage); break;
case "PowerAccent": type = typeof(PowerAccentPage); break;
case "RegistryPreview": type = typeof(RegistryPreviewPage); break;
case "MeasureTool": type = typeof(MeasureToolPage); break;
case "ShortcutGuide": type = typeof(ShortcutGuidePage); break;
case "PowerOCR": type = typeof(PowerOcrPage); break;
case "VideoConference": type = typeof(VideoConferencePage); break;
}
NavigationService.Navigate(type);
}
private void EnabledChangedOnUI(DashboardListItem dashboardListItem) private void EnabledChangedOnUI(DashboardListItem dashboardListItem)
{ {
Views.ShellPage.UpdateGeneralSettingsCallback(dashboardListItem.Tag, dashboardListItem.IsEnabled); Views.ShellPage.UpdateGeneralSettingsCallback(dashboardListItem.Tag, dashboardListItem.IsEnabled);
@ -466,35 +161,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
generalSettingsConfig = _settingsRepository.SettingsConfig; generalSettingsConfig = _settingsRepository.SettingsConfig;
foreach (DashboardListItem item in _allModules) foreach (DashboardListItem item in _allModules)
{ {
switch (item.Tag) item.IsEnabled = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, item.Tag);
{
case "AlwaysOnTop": item.IsEnabled = generalSettingsConfig.Enabled.AlwaysOnTop; break;
case "Awake": item.IsEnabled = generalSettingsConfig.Enabled.Awake; break;
case "ColorPicker": item.IsEnabled = generalSettingsConfig.Enabled.ColorPicker; break;
case "CropAndLock": item.IsEnabled = generalSettingsConfig.Enabled.CropAndLock; break;
case "EnvironmentVariables": item.IsEnabled = generalSettingsConfig.Enabled.EnvironmentVariables; break;
case "FancyZones": item.IsEnabled = generalSettingsConfig.Enabled.FancyZones; break;
case "FileLocksmith": item.IsEnabled = generalSettingsConfig.Enabled.FileLocksmith; break;
case "FindMyMouse": item.IsEnabled = generalSettingsConfig.Enabled.FindMyMouse; break;
case "Hosts": item.IsEnabled = generalSettingsConfig.Enabled.Hosts; break;
case "ImageResizer": item.IsEnabled = generalSettingsConfig.Enabled.ImageResizer; break;
case "KeyboardManager": item.IsEnabled = generalSettingsConfig.Enabled.KeyboardManager; break;
case "MouseHighlighter": item.IsEnabled = generalSettingsConfig.Enabled.MouseHighlighter; break;
case "MouseJump": item.IsEnabled = generalSettingsConfig.Enabled.MouseJump; break;
case "MousePointerCrosshairs": item.IsEnabled = generalSettingsConfig.Enabled.MousePointerCrosshairs; break;
case "MouseWithoutBorders": item.IsEnabled = generalSettingsConfig.Enabled.MouseWithoutBorders; break;
case "PastePlain": item.IsEnabled = generalSettingsConfig.Enabled.PastePlain; break;
case "Peek": item.IsEnabled = generalSettingsConfig.Enabled.Peek; break;
case "PowerRename": item.IsEnabled = generalSettingsConfig.Enabled.PowerRename; break;
case "PowerLauncher": item.IsEnabled = generalSettingsConfig.Enabled.PowerLauncher; break;
case "PowerAccent": item.IsEnabled = generalSettingsConfig.Enabled.PowerAccent; break;
case "RegistryPreview": item.IsEnabled = generalSettingsConfig.Enabled.RegistryPreview; break;
case "MeasureTool": item.IsEnabled = generalSettingsConfig.Enabled.MeasureTool; break;
case "ShortcutGuide": item.IsEnabled = generalSettingsConfig.Enabled.ShortcutGuide; break;
case "PowerOCR": item.IsEnabled = generalSettingsConfig.Enabled.PowerOCR; break;
case "VideoConference": item.IsEnabled = generalSettingsConfig.Enabled.VideoConference; break;
}
if (item.IsEnabled) if (item.IsEnabled)
{ {
ActiveModules.Add(item); ActiveModules.Add(item);
@ -509,6 +176,38 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
OnPropertyChanged(nameof(DisabledModules)); OnPropertyChanged(nameof(DisabledModules));
} }
private ObservableCollection<DashboardModuleItem> GetModuleItems(ModuleType moduleType)
{
return moduleType switch
{
ModuleType.AlwaysOnTop => GetModuleItemsAlwaysOnTop(),
ModuleType.Awake => GetModuleItemsAwake(),
ModuleType.ColorPicker => GetModuleItemsColorPicker(),
ModuleType.CropAndLock => GetModuleItemsCropAndLock(),
ModuleType.EnvironmentVariables => GetModuleItemsEnvironmentVariables(),
ModuleType.FancyZones => GetModuleItemsFancyZones(),
ModuleType.FileLocksmith => GetModuleItemsFileLocksmith(),
ModuleType.FindMyMouse => GetModuleItemsFindMyMouse(),
ModuleType.Hosts => GetModuleItemsHosts(),
ModuleType.ImageResizer => GetModuleItemsImageResizer(),
ModuleType.KeyboardManager => GetModuleItemsKeyboardManager(),
ModuleType.MouseHighlighter => GetModuleItemsMouseHighlighter(),
ModuleType.MouseJump => GetModuleItemsMouseJump(),
ModuleType.MousePointerCrosshairs => GetModuleItemsMousePointerCrosshairs(),
ModuleType.MouseWithoutBorders => GetModuleItemsMouseWithoutBorders(),
ModuleType.PastePlain => GetModuleItemsPastePlain(),
ModuleType.Peek => GetModuleItemsPeek(),
ModuleType.PowerRename => GetModuleItemsPowerRename(),
ModuleType.PowerLauncher => GetModuleItemsPowerLauncher(),
ModuleType.PowerAccent => GetModuleItemsPowerAccent(),
ModuleType.RegistryPreview => GetModuleItemsRegistryPreview(),
ModuleType.MeasureTool => GetModuleItemsMeasureTool(),
ModuleType.ShortcutGuide => GetModuleItemsShortcutGuide(),
ModuleType.PowerOCR => GetModuleItemsPowerOCR(),
_ => new ObservableCollection<DashboardModuleItem>(), // never called, all values listed above
};
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsAlwaysOnTop() private ObservableCollection<DashboardModuleItem> GetModuleItemsAlwaysOnTop()
{ {
ISettingsRepository<AlwaysOnTopSettings> moduleSettingsRepository = SettingsRepository<AlwaysOnTopSettings>.GetInstance(new SettingsUtils()); ISettingsRepository<AlwaysOnTopSettings> moduleSettingsRepository = SettingsRepository<AlwaysOnTopSettings>.GetInstance(new SettingsUtils());
@ -668,7 +367,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
return new ObservableCollection<DashboardModuleItem>(list); return new ObservableCollection<DashboardModuleItem>(list);
} }
private ObservableCollection<DashboardModuleItem> GetModuleItemsMouseCrosshairs() private ObservableCollection<DashboardModuleItem> GetModuleItemsMousePointerCrosshairs()
{ {
ISettingsRepository<MousePointerCrosshairsSettings> moduleSettingsRepository = SettingsRepository<MousePointerCrosshairsSettings>.GetInstance(new SettingsUtils()); ISettingsRepository<MousePointerCrosshairsSettings> moduleSettingsRepository = SettingsRepository<MousePointerCrosshairsSettings>.GetInstance(new SettingsUtils());
var list = new List<DashboardModuleItem> var list = new List<DashboardModuleItem>
@ -716,7 +415,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
return new ObservableCollection<DashboardModuleItem>(list); return new ObservableCollection<DashboardModuleItem>(list);
} }
private ObservableCollection<DashboardModuleItem> GetModuleItemsRun() private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerLauncher()
{ {
ISettingsRepository<PowerLauncherSettings> moduleSettingsRepository = SettingsRepository<PowerLauncherSettings>.GetInstance(new SettingsUtils()); ISettingsRepository<PowerLauncherSettings> moduleSettingsRepository = SettingsRepository<PowerLauncherSettings>.GetInstance(new SettingsUtils());
var list = new List<DashboardModuleItem> var list = new List<DashboardModuleItem>
@ -755,7 +454,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
return new ObservableCollection<DashboardModuleItem>(list); return new ObservableCollection<DashboardModuleItem>(list);
} }
private ObservableCollection<DashboardModuleItem> GetModuleItemsScreenRuler() private ObservableCollection<DashboardModuleItem> GetModuleItemsMeasureTool()
{ {
ISettingsRepository<MeasureToolSettings> moduleSettingsRepository = SettingsRepository<MeasureToolSettings>.GetInstance(new SettingsUtils()); ISettingsRepository<MeasureToolSettings> moduleSettingsRepository = SettingsRepository<MeasureToolSettings>.GetInstance(new SettingsUtils());
var list = new List<DashboardModuleItem> var list = new List<DashboardModuleItem>

View File

@ -4,9 +4,9 @@
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Threading.Tasks;
using global::PowerToys.GPOWrapper; using global::PowerToys.GPOWrapper;
using Microsoft.PowerToys.Settings.UI.Flyout; using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
@ -30,86 +30,32 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
generalSettingsConfig = settingsRepository.SettingsConfig; generalSettingsConfig = settingsRepository.SettingsConfig;
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage); generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
FlyoutMenuItems = new ObservableCollection<FlyoutMenuItem>(); FlyoutMenuItems = new ObservableCollection<FlyoutMenuItem>();
resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader; foreach (ModuleType moduleType in Enum.GetValues(typeof(ModuleType)))
{
AddFlyoutMenuItem("AlwaysOnTop", generalSettingsConfig.Enabled.AlwaysOnTop, "AlwaysOnTop/ModuleTitle", "AlwaysOnTop"); AddFlyoutMenuItem(moduleType);
AddFlyoutMenuItem("Awake", generalSettingsConfig.Enabled.Awake, "Awake/ModuleTitle", "Awake"); }
AddFlyoutMenuItem("ColorPicker", generalSettingsConfig.Enabled.ColorPicker, "ColorPicker/ModuleTitle", "ColorPicker");
AddFlyoutMenuItem("CropAndLock", generalSettingsConfig.Enabled.CropAndLock, "CropAndLock/ModuleTitle", "CropAndLock");
AddFlyoutMenuItem("EnvironmentVariables", generalSettingsConfig.Enabled.EnvironmentVariables, "EnvironmentVariables/ModuleTitle", "EnvironmentVariables");
AddFlyoutMenuItem("FancyZones", generalSettingsConfig.Enabled.FancyZones, "FancyZones/ModuleTitle", "FancyZones");
AddFlyoutMenuItem("FileLocksmith", generalSettingsConfig.Enabled.FileLocksmith, "FileLocksmith/ModuleTitle", "FileLocksmith");
AddFlyoutMenuItem("FindMyMouse", generalSettingsConfig.Enabled.FindMyMouse, "MouseUtils_FindMyMouse/Header", "FindMyMouse");
AddFlyoutMenuItem("Hosts", generalSettingsConfig.Enabled.Hosts, "Hosts/ModuleTitle", "Hosts");
AddFlyoutMenuItem("ImageResizer", generalSettingsConfig.Enabled.ImageResizer, "ImageResizer/ModuleTitle", "ImageResizer");
AddFlyoutMenuItem("KeyboardManager", generalSettingsConfig.Enabled.KeyboardManager, "KeyboardManager/ModuleTitle", "KeyboardManager");
AddFlyoutMenuItem("MouseHighlighter", generalSettingsConfig.Enabled.MouseHighlighter, "MouseUtils_MouseHighlighter/Header", "MouseHighlighter");
AddFlyoutMenuItem("MouseJump", generalSettingsConfig.Enabled.MouseJump, "MouseUtils_MouseJump/Header", "MouseJump");
AddFlyoutMenuItem("MousePointerCrosshairs", generalSettingsConfig.Enabled.MousePointerCrosshairs, "MouseUtils_MousePointerCrosshairs/Header", "MouseCrosshairs");
AddFlyoutMenuItem("MouseWithoutBorders", generalSettingsConfig.Enabled.MouseWithoutBorders, "MouseWithoutBorders/ModuleTitle", "MouseWithoutBorders");
AddFlyoutMenuItem("PastePlain", generalSettingsConfig.Enabled.PastePlain, "PastePlain/ModuleTitle", "PastePlain");
AddFlyoutMenuItem("Peek", generalSettingsConfig.Enabled.Peek, "Peek/ModuleTitle", "Peek");
AddFlyoutMenuItem("PowerRename", generalSettingsConfig.Enabled.PowerRename, "PowerRename/ModuleTitle", "PowerRename");
AddFlyoutMenuItem("PowerLauncher", generalSettingsConfig.Enabled.PowerLauncher, "PowerLauncher/ModuleTitle", "PowerToysRun");
AddFlyoutMenuItem("PowerAccent", generalSettingsConfig.Enabled.PowerAccent, "QuickAccent/ModuleTitle", "PowerAccent");
AddFlyoutMenuItem("RegistryPreview", generalSettingsConfig.Enabled.RegistryPreview, "RegistryPreview/ModuleTitle", "RegistryPreview");
AddFlyoutMenuItem("MeasureTool", generalSettingsConfig.Enabled.MeasureTool, "MeasureTool/ModuleTitle", "ScreenRuler");
AddFlyoutMenuItem("ShortcutGuide", generalSettingsConfig.Enabled.ShortcutGuide, "ShortcutGuide/ModuleTitle", "ShortcutGuide");
AddFlyoutMenuItem("PowerOCR", generalSettingsConfig.Enabled.PowerOCR, "TextExtractor/ModuleTitle", "PowerOCR");
// set the callback functions value to handle outgoing IPC message. // set the callback functions value to handle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc; SendConfigMSG = ipcMSGCallBackFunc;
} }
private void AddFlyoutMenuItem(string moduleName, bool isModuleEnabled, string moduleLabelResourceName, string moduleFluentIconName) private void AddFlyoutMenuItem(ModuleType moduleType)
{ {
GpoRuleConfigured gpo = GetModuleGpoConfiguration(moduleName); GpoRuleConfigured gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
FlyoutMenuItems.Add(new FlyoutMenuItem() FlyoutMenuItems.Add(new FlyoutMenuItem()
{ {
Label = resourceLoader.GetString(moduleLabelResourceName), Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && isModuleEnabled), IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType)),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled, IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Tag = moduleName, Tag = moduleType,
Icon = $"ms-appx:///Assets/Settings/FluentIcons/FluentIcons{moduleFluentIconName}.png", Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
EnabledChangedCallback = EnabledChangedOnUI, EnabledChangedCallback = EnabledChangedOnUI,
}); });
} }
private GpoRuleConfigured GetModuleGpoConfiguration(string moduleName)
{
switch (moduleName)
{
case "AlwaysOnTop": return GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue();
case "Awake": return GPOWrapper.GetConfiguredAwakeEnabledValue();
case "ColorPicker": return GPOWrapper.GetConfiguredColorPickerEnabledValue();
case "CropAndLock": return GPOWrapper.GetConfiguredCropAndLockEnabledValue();
case "EnvironmentVariables": return GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue();
case "FancyZones": return GPOWrapper.GetConfiguredFancyZonesEnabledValue();
case "FileLocksmith": return GPOWrapper.GetConfiguredFileLocksmithEnabledValue();
case "FindMyMouse": return GPOWrapper.GetConfiguredFindMyMouseEnabledValue();
case "Hosts": return GPOWrapper.GetConfiguredHostsFileEditorEnabledValue();
case "ImageResizer": return GPOWrapper.GetConfiguredImageResizerEnabledValue();
case "KeyboardManager": return GPOWrapper.GetConfiguredKeyboardManagerEnabledValue();
case "MouseHighlighter": return GPOWrapper.GetConfiguredMouseHighlighterEnabledValue();
case "MouseJump": return GPOWrapper.GetConfiguredMouseJumpEnabledValue();
case "MousePointerCrosshairs": return GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue();
case "MouseWithoutBorders": return GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue();
case "PastePlain": return GPOWrapper.GetConfiguredPastePlainEnabledValue();
case "Peek": return GPOWrapper.GetConfiguredPeekEnabledValue();
case "PowerRename": return GPOWrapper.GetConfiguredPowerRenameEnabledValue();
case "PowerLauncher": return GPOWrapper.GetConfiguredPowerLauncherEnabledValue();
case "PowerAccent": return GPOWrapper.GetConfiguredQuickAccentEnabledValue();
case "RegistryPreview": return GPOWrapper.GetConfiguredRegistryPreviewEnabledValue();
case "MeasureTool": return GPOWrapper.GetConfiguredScreenRulerEnabledValue();
case "ShortcutGuide": return GPOWrapper.GetConfiguredShortcutGuideEnabledValue();
case "PowerOCR": return GPOWrapper.GetConfiguredTextExtractorEnabledValue();
default: return GpoRuleConfigured.Unavailable;
}
}
private void EnabledChangedOnUI(FlyoutMenuItem flyoutMenuItem) private void EnabledChangedOnUI(FlyoutMenuItem flyoutMenuItem)
{ {
if (Views.ShellPage.UpdateGeneralSettingsCallback(flyoutMenuItem.Tag, flyoutMenuItem.IsEnabled)) if (Views.ShellPage.UpdateGeneralSettingsCallback(flyoutMenuItem.Tag, flyoutMenuItem.IsEnabled))
@ -124,34 +70,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage); generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChangedOnSettingsPage);
foreach (FlyoutMenuItem item in FlyoutMenuItems) foreach (FlyoutMenuItem item in FlyoutMenuItems)
{ {
switch (item.Tag) item.IsEnabled = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, item.Tag);
{
case "AlwaysOnTop": item.IsEnabled = generalSettingsConfig.Enabled.AlwaysOnTop; break;
case "Awake": item.IsEnabled = generalSettingsConfig.Enabled.Awake; break;
case "ColorPicker": item.IsEnabled = generalSettingsConfig.Enabled.ColorPicker; break;
case "CropAndLock": item.IsEnabled = generalSettingsConfig.Enabled.CropAndLock; break;
case "EnvironmentVariables": item.IsEnabled = generalSettingsConfig.Enabled.EnvironmentVariables; break;
case "FancyZones": item.IsEnabled = generalSettingsConfig.Enabled.FancyZones; break;
case "FileLocksmith": item.IsEnabled = generalSettingsConfig.Enabled.FileLocksmith; break;
case "FindMyMouse": item.IsEnabled = generalSettingsConfig.Enabled.FindMyMouse; break;
case "Hosts": item.IsEnabled = generalSettingsConfig.Enabled.Hosts; break;
case "ImageResizer": item.IsEnabled = generalSettingsConfig.Enabled.ImageResizer; break;
case "KeyboardManager": item.IsEnabled = generalSettingsConfig.Enabled.KeyboardManager; break;
case "MouseHighlighter": item.IsEnabled = generalSettingsConfig.Enabled.MouseHighlighter; break;
case "MouseJump": item.IsEnabled = generalSettingsConfig.Enabled.MouseJump; break;
case "MousePointerCrosshairs": item.IsEnabled = generalSettingsConfig.Enabled.MousePointerCrosshairs; break;
case "MouseWithoutBorders": item.IsEnabled = generalSettingsConfig.Enabled.MouseWithoutBorders; break;
case "PastePlain": item.IsEnabled = generalSettingsConfig.Enabled.PastePlain; break;
case "Peek": item.IsEnabled = generalSettingsConfig.Enabled.Peek; break;
case "PowerRename": item.IsEnabled = generalSettingsConfig.Enabled.PowerRename; break;
case "PowerLauncher": item.IsEnabled = generalSettingsConfig.Enabled.PowerLauncher; break;
case "PowerAccent": item.IsEnabled = generalSettingsConfig.Enabled.PowerAccent; break;
case "RegistryPreview": item.IsEnabled = generalSettingsConfig.Enabled.RegistryPreview; break;
case "MeasureTool": item.IsEnabled = generalSettingsConfig.Enabled.MeasureTool; break;
case "ShortcutGuide": item.IsEnabled = generalSettingsConfig.Enabled.ShortcutGuide; break;
case "PowerOCR": item.IsEnabled = generalSettingsConfig.Enabled.PowerOCR; break;
case "VideoConference": item.IsEnabled = generalSettingsConfig.Enabled.VideoConference; break;
}
} }
} }
} }

View File

@ -5,7 +5,7 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Microsoft.UI.Xaml; using ManagedCommon;
namespace Microsoft.PowerToys.Settings.UI.ViewModels namespace Microsoft.PowerToys.Settings.UI.ViewModels
{ {
@ -20,7 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
public string ToolTip { get; set; } public string ToolTip { get; set; }
public string Tag { get; set; } public ModuleType Tag { get; set; }
public bool IsLocked { get; set; } public bool IsLocked { get; set; }

View File

@ -5,10 +5,12 @@
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using global::PowerToys.GPOWrapper; using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
using Microsoft.PowerToys.Settings.UI.Views; using Microsoft.Windows.ApplicationModel.Resources;
namespace Microsoft.PowerToys.Settings.UI.ViewModels namespace Microsoft.PowerToys.Settings.UI.ViewModels
{ {
@ -21,6 +23,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private GeneralSettings generalSettingsConfig; private GeneralSettings generalSettingsConfig;
private UpdatingSettings updatingSettingsConfig; private UpdatingSettings updatingSettingsConfig;
private ISettingsRepository<GeneralSettings> _settingsRepository; private ISettingsRepository<GeneralSettings> _settingsRepository;
private ResourceLoader resourceLoader;
private Func<string, int> SendIPCMessage { get; } private Func<string, int> SendIPCMessage { get; }
@ -32,112 +35,18 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
// set the callback functions value to handle outgoing IPC message. // set the callback functions value to handle outgoing IPC message.
SendIPCMessage = ipcMSGCallBackFunc; SendIPCMessage = ipcMSGCallBackFunc;
var resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader; resourceLoader = ResourceLoaderInstance.ResourceLoader;
FlyoutMenuItems = new ObservableCollection<FlyoutMenuItem>(); FlyoutMenuItems = new ObservableCollection<FlyoutMenuItem>();
if (GPOWrapper.GetConfiguredColorPickerEnabledValue() != GpoRuleConfigured.Disabled)
{
FlyoutMenuItems.Add(new FlyoutMenuItem()
{
Label = resourceLoader.GetString("ColorPicker/ModuleTitle"),
Tag = "ColorPicker",
Visible = generalSettingsConfig.Enabled.ColorPicker,
ToolTip = SettingsRepository<ColorPickerSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(),
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsColorPicker.png",
});
}
if (GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue() != GpoRuleConfigured.Disabled) AddFlyoutMenuItem(ModuleType.ColorPicker);
{ AddFlyoutMenuItem(ModuleType.EnvironmentVariables);
FlyoutMenuItems.Add(new FlyoutMenuItem() AddFlyoutMenuItem(ModuleType.FancyZones);
{ AddFlyoutMenuItem(ModuleType.Hosts);
Label = resourceLoader.GetString("EnvironmentVariables/ModuleTitle"), AddFlyoutMenuItem(ModuleType.PowerLauncher);
Tag = "EnvironmentVariables", AddFlyoutMenuItem(ModuleType.PowerOCR);
Visible = generalSettingsConfig.Enabled.EnvironmentVariables, AddFlyoutMenuItem(ModuleType.RegistryPreview);
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsEnvironmentVariables.png", AddFlyoutMenuItem(ModuleType.MeasureTool);
}); AddFlyoutMenuItem(ModuleType.ShortcutGuide);
}
if (GPOWrapper.GetConfiguredFancyZonesEnabledValue() != GpoRuleConfigured.Disabled)
{
FlyoutMenuItems.Add(new FlyoutMenuItem()
{
Label = resourceLoader.GetString("FZEditorString"),
Tag = "FancyZones",
Visible = generalSettingsConfig.Enabled.FancyZones,
ToolTip = SettingsRepository<FancyZonesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.FancyzonesEditorHotkey.Value.ToString(),
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsFancyZones.png",
});
}
if (GPOWrapper.GetConfiguredHostsFileEditorEnabledValue() != GpoRuleConfigured.Disabled)
{
FlyoutMenuItems.Add(new FlyoutMenuItem()
{
Label = resourceLoader.GetString("Hosts/ModuleTitle"),
Tag = "Hosts",
Visible = generalSettingsConfig.Enabled.Hosts,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsHosts.png",
});
}
if (GPOWrapper.GetConfiguredPowerLauncherEnabledValue() != GpoRuleConfigured.Disabled)
{
FlyoutMenuItems.Add(new FlyoutMenuItem()
{
Label = resourceLoader.GetString("PowerLauncher/ModuleTitle"),
Tag = "PowerLauncher",
Visible = generalSettingsConfig.Enabled.PowerLauncher,
ToolTip = SettingsRepository<PowerLauncherSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenPowerLauncher.ToString(),
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsPowerToysRun.png",
});
}
if (GPOWrapper.GetConfiguredTextExtractorEnabledValue() != GpoRuleConfigured.Disabled)
{
FlyoutMenuItems.Add(new FlyoutMenuItem()
{
Label = resourceLoader.GetString("TextExtractor/ModuleTitle"),
Tag = "PowerOCR",
Visible = generalSettingsConfig.Enabled.PowerOCR,
ToolTip = SettingsRepository<PowerOcrSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(),
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsPowerOcr.png",
});
}
if (GPOWrapper.GetConfiguredRegistryPreviewEnabledValue() != GpoRuleConfigured.Disabled)
{
FlyoutMenuItems.Add(new FlyoutMenuItem()
{
Label = resourceLoader.GetString("RegistryPreview/ModuleTitle"),
Tag = "RegistryPreview",
Visible = generalSettingsConfig.Enabled.RegistryPreview,
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsRegistryPreview.png",
});
}
if (GPOWrapper.GetConfiguredScreenRulerEnabledValue() != GpoRuleConfigured.Disabled)
{
FlyoutMenuItems.Add(new FlyoutMenuItem()
{
Label = resourceLoader.GetString("MeasureTool/ModuleTitle"),
Tag = "MeasureTool",
Visible = generalSettingsConfig.Enabled.MeasureTool,
ToolTip = SettingsRepository<MeasureToolSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(),
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsScreenRuler.png",
});
}
if (GPOWrapper.GetConfiguredShortcutGuideEnabledValue() != GpoRuleConfigured.Disabled)
{
FlyoutMenuItems.Add(new FlyoutMenuItem()
{
Label = resourceLoader.GetString("ShortcutGuide/ModuleTitle"),
Tag = "ShortcutGuide",
Visible = generalSettingsConfig.Enabled.ShortcutGuide,
ToolTip = SettingsRepository<ShortcutGuideSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenShortcutGuide.ToString(),
Icon = "ms-appx:///Assets/Settings/FluentIcons/FluentIconsShortcutGuide.png",
});
}
if (updatingSettingsConfig == null) if (updatingSettingsConfig == null)
{ {
@ -156,23 +65,44 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
} }
} }
private void AddFlyoutMenuItem(ModuleType moduleType)
{
if (ModuleHelper.GetModuleGpoConfiguration(moduleType) == GpoRuleConfigured.Disabled)
{
return;
}
FlyoutMenuItems.Add(new FlyoutMenuItem()
{
Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
Tag = moduleType,
Visible = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType),
ToolTip = GetModuleTooltip(moduleType),
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
});
}
private string GetModuleTooltip(ModuleType moduleType)
{
return moduleType switch
{
ModuleType.ColorPicker => SettingsRepository<ColorPickerSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(),
ModuleType.FancyZones => SettingsRepository<FancyZonesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.FancyzonesEditorHotkey.Value.ToString(),
ModuleType.PowerLauncher => SettingsRepository<PowerLauncherSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenPowerLauncher.ToString(),
ModuleType.PowerOCR => SettingsRepository<PowerOcrSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(),
ModuleType.MeasureTool => SettingsRepository<MeasureToolSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.ToString(),
ModuleType.ShortcutGuide => SettingsRepository<ShortcutGuideSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenShortcutGuide.ToString(),
_ => string.Empty,
};
}
private void ModuleEnabledChanged() private void ModuleEnabledChanged()
{ {
generalSettingsConfig = _settingsRepository.SettingsConfig; generalSettingsConfig = _settingsRepository.SettingsConfig;
generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChanged); generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChanged);
foreach (FlyoutMenuItem item in FlyoutMenuItems) foreach (FlyoutMenuItem item in FlyoutMenuItems)
{ {
switch (item.Tag) item.Visible = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, item.Tag);
{
case "ColorPicker": item.Visible = generalSettingsConfig.Enabled.ColorPicker; break;
case "FancyZones": item.Visible = generalSettingsConfig.Enabled.FancyZones; break;
case "Hosts": item.Visible = generalSettingsConfig.Enabled.Hosts; break;
case "PowerLauncher": item.Visible = generalSettingsConfig.Enabled.PowerLauncher; break;
case "PowerOCR": item.Visible = generalSettingsConfig.Enabled.PowerOCR; break;
case "RegistryPreview": item.Visible = generalSettingsConfig.Enabled.RegistryPreview; break;
case "MeasureTool": item.Visible = generalSettingsConfig.Enabled.MeasureTool; break;
case "ShortcutGuide": item.Visible = generalSettingsConfig.Enabled.ShortcutGuide; break;
}
} }
} }

View File

@ -28,10 +28,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
"CUR", "CUR",
"HR", "HR",
"CZ", "CZ",
"DK",
"GA", "GA",
"GD", "GD",
"NL", "NL",
"EST", "EST",
"FI",
"FR", "FR",
"DE", "DE",
"HE", "HE",