diff --git a/.configurations/configuration.dsc.yaml b/.configurations/configuration.dsc.yaml index a6256da51268..df3eeea44101 100644 --- a/.configurations/configuration.dsc.yaml +++ b/.configurations/configuration.dsc.yaml @@ -12,7 +12,6 @@ properties: id: vsPackage directives: description: Install Visual Studio 2022 Community (Any edition will work) - allowPrerelease: true settings: id: Microsoft.VisualStudio.2022.Community source: winget diff --git a/.configurations/configuration.vsEnterprise.dsc.yaml b/.configurations/configuration.vsEnterprise.dsc.yaml index 34d73f497558..84e05ed5119f 100644 --- a/.configurations/configuration.vsEnterprise.dsc.yaml +++ b/.configurations/configuration.vsEnterprise.dsc.yaml @@ -12,7 +12,6 @@ properties: id: vsPackage directives: description: Install Visual Studio 2022 Enterprise (Any edition will work) - allowPrerelease: true settings: id: Microsoft.VisualStudio.2022.Enterprise source: winget diff --git a/.configurations/configuration.vsProfessional.dsc.yaml b/.configurations/configuration.vsProfessional.dsc.yaml index 3c08d05856e2..6ac0babf9f09 100644 --- a/.configurations/configuration.vsProfessional.dsc.yaml +++ b/.configurations/configuration.vsProfessional.dsc.yaml @@ -12,7 +12,6 @@ properties: id: vsPackage directives: description: Install Visual Studio 2022 Professional (Any edition will work) - allowPrerelease: true settings: id: Microsoft.VisualStudio.2022.Professional source: winget diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3d1b740d57be..96e0bafa150d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,16 +1,16 @@ # Protect `.github` folder except the spell-check rules inside it. (The exception happens by not defining any owner user or group for the path.) # Protection of the spell-check rules makes no sense as it needs to be changed in nearly every PR. -/.github/ @crutkas @DHowett @ethanfangg +/.github/ @microsoft/powertoys-code-owners /.github/actions/spell-check/ # locking down pipeline folder -/.pipelines/ @crutkas @DHowett @ethanfangg +/.pipelines/ @microsoft/powertoys-code-owners # locking down nuget config -nuget.config @crutkas @DHowett @ethanfangg -packages.config @crutkas @DHowett @ethanfangg +nuget.config @microsoft/powertoys-code-owners +packages.config @microsoft/powertoys-code-owners # locking down files that should not change -LICENSE @crutkas @DHowett @ethanfangg -SECURITY.md @crutkas @DHowett @ethanfangg -CODE_OF_CONDUCT.md @crutkas @DHowett @ethanfangg +LICENSE @microsoft/powertoys-code-owners +SECURITY.md @microsoft/powertoys-code-owners +CODE_OF_CONDUCT.md @microsoft/powertoys-code-owners diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f2eb897a4d56..37ba10bc4d85 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -77,9 +77,9 @@ body: - Shortcut Guide - System tray interaction - TextExtractor - - Video Conference Mute - Workspaces - Welcome / PowerToys Tour window + - ZoomIt validations: required: true diff --git a/.github/ISSUE_TEMPLATE/translation_issue.yml b/.github/ISSUE_TEMPLATE/translation_issue.yml index 69787a3ed685..ffddacb9aac8 100644 --- a/.github/ISSUE_TEMPLATE/translation_issue.yml +++ b/.github/ISSUE_TEMPLATE/translation_issue.yml @@ -51,9 +51,9 @@ body: - Shortcut Guide - System tray interaction - TextExtractor - - Video Conference Mute - Workspaces - Welcome / PowerToys Tour window + - ZoomIt validations: required: true - type: input diff --git a/.github/actions/spell-check/allow/code.txt b/.github/actions/spell-check/allow/code.txt index 2737b7327c48..787715190015 100644 --- a/.github/actions/spell-check/allow/code.txt +++ b/.github/actions/spell-check/allow/code.txt @@ -21,6 +21,9 @@ Pbgra WHITEONBLACK +# COUNTRIES +RUS + # FILES AYUV @@ -75,7 +78,14 @@ sinclairinat stylecop uipi yinwang - +myaccess +onmicrosoft +aep +epsf +howto +onefuzzconfig +oip +onefuzzingestionpreparationtool # KEYS @@ -87,6 +97,7 @@ EXSEL HOLDENTER HOLDESC HOLDSPACE +HOLDBACKSPACE KBDLLHOOKSTRUCT keyevent LAlt @@ -128,6 +139,9 @@ XBUTTONDOWN XBUTTONUP XDOWN +# Prefix +pcs + # User32.SYSTEM_METRICS_INDEX.cs CLEANBOOT @@ -220,9 +234,32 @@ TABLETPC artanh arsinh arcosh +roundf # Linux dbus anypass +github gpg +https +ssh +ubuntu +workarounds + +# For upgrade to check-spelling v0.0.24 +pwa + +# .NET + +AOT +Aot + +# YML +onefuzz + +# NameInCode +leilzh + +#Tools +OIP diff --git a/.github/actions/spell-check/allow/names.txt b/.github/actions/spell-check/allow/names.txt index 20a09d224187..4941c62e13ce 100644 --- a/.github/actions/spell-check/allow/names.txt +++ b/.github/actions/spell-check/allow/names.txt @@ -23,7 +23,6 @@ registrypreview rooler scoobe shortcutguide -videoconference # USERS @@ -34,6 +33,7 @@ Adoumie Advaith alekhyareddy Aleks +amihaiuc angularsen Anirudha arjunbalgovind @@ -44,7 +44,10 @@ Bartosz betadele betsegaw bricelam +bsky CCcat +chenmy +chemwolf Chinh chrdavis Chrzan @@ -53,6 +56,7 @@ Coplen craigloewen crutkas damienleroy +daverayment davidegiacometti debian Deibisu @@ -61,9 +65,12 @@ Deondre DHowett ductdo Essey +Feng ethanfangg ferraridavide +foxmsft frankychen +Gaarden gaardmark gabime Galaxi @@ -71,8 +78,11 @@ Garside Gershaft Giordani Gokce +gordon +grzhan Guo hanselman +haoliuu Harmath Heiko Hemmerlein @@ -81,25 +91,32 @@ Horvalds Howett htcfreek Huynh +Ionut +jamrobot Jaswal jefflord Jordi jyuwono +kai Kairu Kamra Kantarci Karthick +kaylacinnamon kevinguo Krigun Lambson Laute laviusmotileng +Leilei Luecking Mahalingam Markovic martinchrzan martinmoene Melman +Mengyuan +Mihaiuc Mikhayelyan msft Mykhailo @@ -109,20 +126,25 @@ nathancartlidge Nemeth nielslaute oldnewthing +onegreatworld palenshus pedrolamas +Peiyao peteblois phoboslab Ponten Pooja Pylyp +Qingpeng quachpas Quriz randyrants +rayment ricardosantos riri ritchielawrence robmikh +Russinovich Rutkas ryanbodrug saahmedm @@ -143,17 +165,31 @@ Taras TBM tilovell Triet +urnotdfs waaverecords +wang +Whuihuan +Xiaofeng Xpg +Yaqing +yaqingmi ycv +yeelam Yuniardi yuyoyuppe Zeol +Zhao +Zhaopeng +zhaopy +zhaoqpcn Zoltan Zykova # OTHERS +Bilibili +BVID +capturevideosample cmdow Controlz cortana diff --git a/.github/actions/spell-check/candidate.patterns b/.github/actions/spell-check/candidate.patterns index 4760fcdd18c0..13bcc3b29ff9 100644 --- a/.github/actions/spell-check/candidate.patterns +++ b/.github/actions/spell-check/candidate.patterns @@ -1,3 +1,6 @@ +# D2D +#D?2D + # marker to ignore all code on line ^.*/\* #no-spell-check-line \*/.*$ # marker to ignore all code on line @@ -8,7 +11,7 @@ ^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b # patch hunk comments -^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .* +^@@ -\d+(?:,\d+|) \+\d+(?:,\d+|) @@ .* # git index header index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40} @@ -26,13 +29,13 @@ index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40} # data url in quotes ([`'"])data:(?:[^ `'"].*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1} # data url -data:[-a-zA-Z=;:/0-9+]*,\S* +\bdata:[-a-zA-Z=;:/0-9+]*,\S* # https/http/file urls -#(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|] +#(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/*%?=~_|!:,.;]+[-A-Za-z0-9+&@#/*%=~_|] # mailto urls -mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,} +#mailto:[-a-zA-Z=;:/?%&0-9+@._]{3,} # magnet urls magnet:[?=:\w]+ @@ -152,6 +155,9 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+. # GHSA GHSA(?:-[0-9a-z]{4}){3} +# GitHub actions +\buses:\s+[-\w.]+/[-\w./]+@[-\w.]+ + # GitLab commit \bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b # GitLab merge requests @@ -210,7 +216,7 @@ accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]* # medium link \blink\.medium\.com/[a-zA-Z0-9]+ # medium -\bmedium\.com/\@?[^/\s"]+/[-\w]+ +\bmedium\.com/@?[^/\s"]+/[-\w]+ # microsoft \b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]* @@ -275,7 +281,7 @@ slack://[a-zA-Z0-9?&=]+ [0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b # Twitter markdown -\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\) +\[@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\) # Twitter hashtag \btwitter\.com/hashtag/[\w?_=&]* # Twitter status @@ -330,7 +336,7 @@ ipfs://[0-9a-zA-Z]{3,} [^"\s]+/gitweb/\S+;h=[0-9a-f]+ # HyperKitty lists -/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/ +/archives/list/[^@/]+@[^/\s"]*/message/[^/\s"]*/ # lists /thread\.html/[^"\s]+ @@ -348,7 +354,7 @@ ipfs://[0-9a-zA-Z]{3,} \bopen\.spotify\.com/embed/playlist/\w+ # Mastodon -\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]* +\bmastodon\.[-a-z.]*/(?:media/|@)[?&=0-9a-zA-Z_]* # scastie \bscastie\.scala-lang\.org/[^/]+/\w+ @@ -390,9 +396,9 @@ ipfs://[0-9a-zA-Z]{3,} (?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m # URL escaped characters -\%[0-9A-F][A-F] +%[0-9A-F][A-F](?=[A-Za-z]) # lower URL escaped characters -\%[0-9a-f][a-f](?=[a-z]{2,}) +%[0-9a-f][a-f](?=[a-z]{2,}) # IPv6 \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) @@ -400,7 +406,7 @@ ipfs://[0-9a-zA-Z]{3,} # Punycode \bxn--[-0-9a-z]+ # sha -sha\d+:[0-9]*[a-f]{3,}[0-9a-f]* +sha\d+:[0-9a-f]*?[a-f]{3,}[0-9a-f]* # sha-... -- uses a fancy capture (\\?['"]|")[0-9a-f]{40,}\g{-1} # hex runs @@ -420,10 +426,13 @@ sha\d+:[0-9]*[a-f]{3,}[0-9a-f]* # pki -----BEGIN.*-----END +# pki (base64) +LS0tLS1CRUdJT.* + # uuid: \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: -(?:[\\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 +(?:[\\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=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1} @@ -441,20 +450,47 @@ integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1} Name\[[^\]]+\]=.* # IServiceProvider / isAThing -\b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b) +(?:\b|_)(?:(?:ns|)I|isA)(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b)) # crypt (['"])\$2[ayb]\$.{56}\g{-1} +# apache/old crypt +(['"]|)\$+(?:apr|)1\$+.{8}\$+.{22}\g{-1} + +# sha1 hash +\{SHA\}[-a-zA-Z=;:/0-9+]{3,} + +# machine learning (?) +#\b(?i)ml(?=[a-z]{2,}) + +# python +#\b(?i)py(?!gments|gmy|lon|ramid|ro|th)(?=[a-z]{2,}) + # scrypt / argon \$(?:scrypt|argon\d+[di]*)\$\S+ # go.sum \bh1:\S+ +# scala imports +^import (?:[\w.]|\{\w*?(?:,\s*(?:\w*|\*))+\})+ + # scala modules #("[^"]+"\s*%%?\s*){2,3}"[^"]+" +# container images +image: [-\w./:@]+ + +# Docker images +^\s*FROM\s+\S+:\S+(?:\s+AS\s+\S+|) + +# `docker images` REPOSITORY TAG IMAGE ID CREATED SIZE +\s*\S+/\S+\s+\S+\s+[0-9a-f]{8,}\s+\d+\s+(?:hour|day|week)s ago\s+[\d.]+[KMGT]B + +# Intel intrinsics +_mm_(?!dd)\w+ + # Input to GitHub JSON content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1} @@ -462,34 +498,44 @@ content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1} # 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)(?!%)(?=.*?['"]) +#%(?:(?:(?:hh?|ll?|[jzt])?[diuoxn]|l?[cs]|L?[fega]|p)(?=[a-z]{2,})|(?:X|L?[FEGA])(?=[a-zA-Z]{2,}))(?!%)(?=[_a-zA-Z]+(?!%)\b)(?=.*?['"]) + +# Alternative printf +# %s +%(?:s(?=[a-z]{2,}))(?!%)(?=[_a-zA-Z]+(?!%[^s])\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 -(?|m([|!/@#,;']).*?\g{-1}) # perl qr regex (?|\(.*?\)|([|!/@#,;']).*?\g{-1}) +# perl run +perl(?:\s+-[a-zA-Z]\w*)+ + +# C network byte conversions +#(?:\d|\bh)to(?!ken)(?=[a-z])|to(?=[adhiklpun]\() + # Go regular expressions regexp?\.MustCompile\(`[^`]*`\) @@ -503,14 +549,20 @@ regexp?\.MustCompile\(`[^`]*`\) sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2} # node packages -(["'])\@[^/'" ]+/[^/'" ]+\g{-1} +(["'])@[^/'" ]+/[^/'" ]+\g{-1} # go install go install(?:\s+[a-z]+\.[-@\w/.]+)+ +# pom.xml +<(?:group|artifact)Id>.*?< + # jetbrains schema https://youtrack.jetbrains.com/issue/RSRP-489571 urn:shemas-jetbrains-com +# Debian changelog severity +[-\w]+ \(.*\) (?:\w+|baseline|unstable|experimental); urgency=(?:low|medium|high|emergency|critical)\b + # kubernetes pod status lists # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase \w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+ @@ -518,9 +570,15 @@ urn:shemas-jetbrains-com # kubectl - pods in CrashLoopBackOff \w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+ +# kubernetes applications +\.apps/[-\w]+ + # kubernetes object suffix -[0-9a-f]{10}-\w{5}\s +# kubernetes crd patterns +^\s*pattern: .*$ + # posthog secrets ([`'"])phc_[^"',]+\g{-1} @@ -532,6 +590,9 @@ urn:shemas-jetbrains-com # xcode api botches customObjectInstantitationMethod +# msvc api botches +PrependWithABINamepsace + # configure flags .* \| --\w{2,}.*?(?=\w+\s\w+) @@ -539,21 +600,34 @@ customObjectInstantitationMethod \.fa-[-a-z0-9]+ # bearer auth -(['"])Bear[e][r] .*?\g{-1} +(['"])[Bb]ear[e][r] .*?\g{-1} + +# bearer auth +\b[Bb]ear[e][r]:? [-a-zA-Z=;:/0-9+.]+ # basic auth -(['"])Basic [-a-zA-Z=;:/0-9+]{3,}\g{-1} +(['"])[Bb]asic [-a-zA-Z=;:/0-9+]{3,}\g{-1} # base64 encoded content -([`'"])[-a-zA-Z=;:/0-9+]+=\g{-1} +#([`'"])[-a-zA-Z=;:/0-9+]{3,}=\g{-1} # base64 encoded content in xml/sgml ->[-a-zA-Z=;:/0-9+]+=[-a-zA-Z=;:/0-9+]{3,}== 0.0.22) \\\w{2,}\{ +# American Mathematical Society (AMS) / Doxygen +TeX/AMS + +# File extensions +\*\.[+\w]+, + # eslint "varsIgnorePattern": ".+" +# nolint +nolint:\w+ + # Windows short paths -[/\\][^/\\]{5,6}~\d{1,2}[/\\] +[/\\][^/\\]{5,6}~\d{1,2}(?=[/\\]) + +# Windows Resources with accelerators +\b[A-Z]&[a-z]+\b(?!;) + +# cygwin paths +/cygdrive/[a-zA-Z]/(?:Program Files(?: \(.*?\)| ?)(?:/[-+.~\\/()\w ]+)*|[-+.~\\/()\w])+ # in check-spelling@v0.0.22+, printf markers aren't automatically consumed # printf markers #(? MOZILLA PUBLIC LICENSE v1.1 aaaa abcdefghjkmnpqrstuvxyz abgr ABlocked ABOUTBOX Abug -accctrl Acceleratorkeys ACCEPTFILES ACCESSDENIED ACCESSTOKEN -aclapi AClient AColumn acrt ACTIVATEAPP activationaction +ADDSTRING ADDUNDORECORD ADifferent adml admx -advapi advfirewall AFeature AFFINETRANSFORM AFX AGGREGATABLE +ahk AHybrid akv +ALIGNRIGHT ALarger ALLAPPS +ALLCHILDREN ALLINPUT ALLOWUNDO ALLVIEW @@ -42,6 +40,7 @@ AMPROPSETID amr ANDSCANS animatedvisuals +Animnate ansicolor ANull AOC @@ -53,10 +52,7 @@ APIENTRY APIIs Apm APPBARDATA -appdata APPEXECLINK -Appium -Applicationcan APPLICATIONFRAMEHOST appmanifest APPNAME @@ -69,11 +65,10 @@ AQS ARandom ARCHITEW ARemapped -ari ARPINSTALLLOCATION ARPPRODUCTICON ARRAYSIZE -arw +ARROWKEYS asf AShortcut ASingle @@ -83,17 +78,18 @@ ASSOCSTR ASYNCWINDOWPLACEMENT ASYNCWINDOWPOS atl -atlbase -atlcom atleast -atlfile -atlstr ATRIOX aumid Authenticode +AUTOBUDDY +AUTOCHECKBOX AUTOHIDE +AUTOHSCROLL AUTOMATIONPROPERTIES +AUTORADIOBUTTON Autorun +AUTOTICKS AUTOUPDATE AValid awakeness @@ -104,17 +100,23 @@ backtracer bbwe bck BESTEFFORT +bezelled bhid BIF bigbar bigobj binlog +binres BITMAPFILEHEADER bitmapimage BITMAPINFO BITMAPINFOHEADER +Bitmaps +BITSPERPEL BITSPIXEL bla +BLACKFRAME +BLENDFUNCTION Blockquotes blogs Blt @@ -124,8 +126,6 @@ bmi bms BNumber BODGY -BOKMAL -bootstrapper BOOTSTRAPPERINSTALLFOLDER bostrot BOTTOMALIGN @@ -133,6 +133,7 @@ boxmodel BPBF bpmf bpp +Breadcrumb Browsable BROWSEINFO bsd @@ -147,6 +148,7 @@ BVal BValue byapp BYPOSITION +CALCRECT CALG callbackptr calpwstr @@ -163,23 +165,20 @@ CCom CContext CDeclaration CDEF -cdpx CElems CENTERALIGN -ceq certlm certmgr cfp -cguid CHANGECBCHAIN changecursor CHILDACTIVATE CHILDWINDOW +CHOOSEFONT cidl cim CImage cla -clangformat CLASSDC CLASSNOTAVAILABLE clickable @@ -195,21 +194,16 @@ CLSCTX Clusion cmder CMDNOTFOUNDMODULEINTERFACE -Cmds CMIC CMINVOKECOMMANDINFO CMINVOKECOMMANDINFOEX CMock CMONITORS -cmpgt cmph -cne CNF coclass -codeofconduct codereview Codespaces -codicon COINIT colorconv colorformat @@ -221,36 +215,28 @@ comdef comdlg comexp cominterop -commandline -commctrl -commdlg compmgmt COMPOSITIONFULL -comsupp -comsuppw -comsuppwd -comutil CONFIGW CONFLICTINGMODIFIERKEY CONFLICTINGMODIFIERSHORTCUT CONOUT -consts -contentdialog contentfiles CONTEXTHELP CONTEXTMENUHANDLER CONTROLL CONTROLPARENT copiedcolorrepresentation +COPYPEN COREWINDOW cotaskmem COULDNOT countof cph +cplusplus CPower -cppblog -cppwinrt createdump +CREATEPROCESS CREATESCHEDULEDTASK CREATESTRUCT CREATEWINDOWFAILED @@ -258,15 +244,14 @@ CRECT CRH critsec Crossdevice -CRSEL -crw CSearch CSettings cso CSRW CStyle -CSY CTest +CTEXT +CTLCOLORSTATIC currentculture CURRENTDIR CURSORINFO @@ -276,7 +261,6 @@ CUSTOMACTIONTEST CVal cvd CVirtual -cvtepu cxfksword CXSCREEN CXSMICON @@ -292,17 +276,13 @@ datareader datatracker dataversion Dayof -Dbghelp DBLCLKS DBLEPSILON DCapture DCBA DCOM -dcommon -dcomp DComposition -dcr -dcs +DCR ddd DDEIf DDevice @@ -328,28 +308,35 @@ DELA DELETEDKEYIMAGE DELETESCANS deletethis +DEMOTYPE DENORMAL depersist deprioritized DESELECTOTHERS +DESIGNINFO DESKTOPABSOLUTEEDITING DESKTOPABSOLUTEPARSING desktopshorcutinstalled -desktopwindowxamlsource devblogs devdocs devenum devmgmt +DEVMODE DEVMODEW DEVMON -devpkey DEVSOURCE +DGR +DIALOGEX DIIRFLAG dimm DISABLEASACTIONKEY +DISABLENOSCROLL diskmgmt DISPLAYCHANGE DISPLAYCONFIG +DISPLAYFLAGS +DISPLAYFREQUENCY +DISPLAYORIENTATION displayname divyan Dlg @@ -372,12 +359,14 @@ DRAWCLIPBOARD DRAWFRAME drawingcolor dreamsofameaningfullife -drf drivedetectionwarning +DROPFILES dshow DSTINVERT +DSurface +DTexture DUMMYUNIONNAME -dutil +Dutil DVASPECT DVASPECTINFO DVD @@ -404,28 +393,21 @@ DWORDLONG dworigin dwrite dxgi -dxgidebug -dxgiformat -dxguid easeofaccess ecount EData Edid EDITKEYBOARD -editkeyboardwindow EDITSHORTCUTS -editshortcutswindow +EDITTEXT EFile -eip ekus -emmintrin -Emoji ENABLEDELAYEDEXPANSION -enabledisable ENABLEDPOPUP +ENABLETAB +ENABLETEMPLATE encodedlaunch encryptor -endpointvolume ENDSESSION ENSUREVISIBLE ENTERSIZEMOVE @@ -442,14 +424,13 @@ ERRORTITLE erwrite ESettings esrp +ETDT etl etw -EUQ +eula eurochange eventlog eventvwr -everytime -evntrace evt EWXFORCE EWXFORCEIFHUNG @@ -461,7 +442,6 @@ examplehandler examplepowertoy EXAND EXCLUDEFROMCAPTURE -exdisp executionpolicy exename EXITSIZEMOVE @@ -475,6 +455,7 @@ exsb exstyle EXTENDEDKEY EXTENDEDVERBS +EXTRALIGHT EXTRINSICPROPERTIES eyetracker FANCYZONESDRAWLAYOUTTEST @@ -485,12 +466,14 @@ fff FILEEXPLORER FILEFLAGS FILEFLAGSMASK +FILEINFOSIG FILELOCKSMITH FILELOCKSMITHCONTEXTMENU FILELOCKSMITHEXT FILELOCKSMITHLIBINTEROP FILEMUSTEXIST FILEOP +FILEOPENDIALOGOPTIONS FILEOS FILESUBTYPE FILESYSPATH @@ -498,9 +481,11 @@ Filetime FILEVERSION Filtergraph Filterkeyboard +FILTERMODE Filterx findfast FIXEDFILEINFO +FIXEDSYS flac flyouts FMask @@ -508,7 +493,10 @@ FOF FOFX FOLDERID folderpath +FONTTYPE +FORCEFILESYSTEM FORCEMINIMIZE +FORMATDLGORD formatetc FORPARSING FRAMECHANGED @@ -516,26 +504,31 @@ frm Froml FROMTOUCH fsmgmt -Functiondiscoverykeys FZE gacutil Gaeilge Gaidhlig +GC'ed GCLP gdi gdiplus +GDIPVER GDISCALED GEmoji GETCLIENTAREAANIMATION +GETCURSEL GETDESKWALLPAPER GETDLGCODE GETDPISCALEDSIZE getfilesiginforedist GETICON +GETHOTKEY GETMINMAXINFO +GETNONCLIENTMETRICS GETPROPERTYSTOREFLAGS GETSCREENSAVERRUNNING GETSECKEY +GETSTICKYKEYS GETTEXTLENGTH GHND GMEM @@ -545,16 +538,14 @@ gpo GPOCA gpp gpu +gradians GSM gtm guiddata -guiddef -guidgenerator GUITHREADINFO GValue gwl GWLP -handlekeyboardhookevent hangeul Hanzi Hardlines @@ -570,6 +561,7 @@ hbm hbmp hbr HBRBACKGROUND +hbrush hcblack HCERTSTORE HCRYPTHASH @@ -577,6 +569,7 @@ HCRYPTPROV hcursor hcwhite hdc +hdr hdrop hdwwiz Helpline @@ -589,18 +582,20 @@ Hiber Hiberboot HIBYTE hicon +HIDEREADONLY HIDEWINDOW -hif +Hif HIMAGELIST himl hinst -hinstance HIWORD HKCC +HKCOMB HKCR HKCU hkey HKLM +HKM HKPD HKU HMD @@ -608,8 +603,11 @@ hmenu hmodule hmonitor homljgmgpmcbpjbnjpfijnhipfkiclkd +HORZRES +HORZSIZE Hostbackdropbrush hotkeycontrol +HOTKEYF hotkeys hotlight hotspot @@ -622,7 +620,6 @@ hrgn hsb HSCROLL hsi -hstring HTCLIENT hthumbnail HTOUCHINPUT @@ -637,39 +634,32 @@ hwnd HWNDFIRST HWNDLAST HWNDNEXT +HWNDPARENT HWNDPREV hyjiacan +IAI IBeam -ICapture -IClass ICONERROR ICONLOCATION -IData +idc +IDCANCEL IDD -IDesktop -IDirect idl idlist -IDOn +IDOK IDR IDXGI -IEnum ietf -IExec IEXPLORE IFACEMETHOD IFACEMETHODIMP IFile -IFilter IGNOREUNKNOWN -IGraphics iid Iindex -iiq -IJson Ijwhost IKs -ILogon +iljxck IMAGEHLP IMAGERESIZERCONTEXTMENU IMAGERESIZEREXT @@ -677,11 +667,15 @@ imageresizerinput imageresizersettings imagingdevices ime +INCONTACT +Indo inetcpl Infobar INFOEXAMPLE Infotip -initguid +INITDIALOG +INITGUID +INITTOLOGFONTSTRUCT inorder INPC inproc @@ -689,7 +683,6 @@ INPUTHARDWARE INPUTKEYBOARD INPUTLANGCHANGED INPUTMOUSE -inputparser INPUTSINK INPUTTYPE INSTALLDESKTOPSHORTCUT @@ -704,50 +697,37 @@ installscopeperuser INSTALLSTARTMENUSHORTCUT INSTALLSTATE Inste -Intelli Interlop INTRESOURCE INVALIDARG invalidoperatioexception ipcmanager -IPlugin -IPower IPREVIEW -ipreviewhandlervisualssetfont -IProperty -IPublic irprops isbi ISearch ISettings -IShell isocpp iss issecret ISSEPARATOR -ITask ith ITHUMBNAIL IUI IUnknown -IWbem -IWeb +IUse IWIC iwr IYUV -jfi jfif jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi -jif jjw jobject jpe jpnime Jsons jsonval -junja jxr -kdc keybd KEYBDDATA KEYBDINPUT @@ -756,7 +736,6 @@ keyboardmanagercommon KEYBOARDMANAGEREDITOR keyboardmanagerstate keyboardmanagerui -keydropdowncontrol KEYEVENTF KEYIMAGE keynum @@ -765,55 +744,60 @@ keyvault KILLFOCUS killrunner kmph -Knownfolders KSPROPERTY Kybd -languagesjson lastcodeanalysissucceeded Lastdevice LASTEXITCODE LAYOUTRTL +lcb LCIDTo -lcl Lclean Ldone +Ldr ldx LEFTSCROLLBAR -lego +LEFTTEXT LError LEVELID LExit lhwnd LIBID -licate +LIMITSIZE +LIMITTEXT lindex +linkid LINKOVERLAY LINQTo listview +LIVEZOOM lld LLKH llkhf -lmcons LMEM LMENU lnks LOADFROMFILE LOBYTE LOCALDISPLAY -LOCALPACKAGE +localpackage LOCALSYSTEM LOCATIONCHANGE LOGFONT LOGFONTW logon LOGPIXELSX +LOGPIXELSY longdate LONGLONG +LONGNAMES lowlevel LOWORD lparam LPBITMAPINFOHEADER +LPCFHOOKPROC LPCITEMIDLIST +LPCLSID lpcmi LPCMINVOKECOMMANDINFO LPCREATESTRUCT @@ -832,7 +816,6 @@ lprc LPSAFEARRAY lpstr lpsz -lpt LPTHREAD LPTOP lptpm @@ -841,12 +824,15 @@ LPTSTR LPW lpwcx lpwndpl +lpv LReader LRESULT LSTATUS lstrcmp lstrcmpi +lstrcpyn lstrlen +LTEXT LTRB LTRREADING luid @@ -856,13 +842,16 @@ LVal LWA lwin LZero +MAGTRANSFORM majortype makecab MAKEINTRESOURCE MAKEINTRESOURCEA MAKEINTRESOURCEW MAKELANGID -makepri +MAKELONG +MAKELPARAM +MAKEWPARAM manifestdependency MAPPEDTOSAMEKEY MAPTOSAMESHORTCUT @@ -872,7 +861,6 @@ MAXIMIZEBOX MAXSHORTCUTSIZE maxversiontested MBR -mdc MDICHILD MDL mdtext @@ -880,32 +868,25 @@ mdtxt mdwn MEDIASUBTYPE mediatype -mef MENUITEMINFO MENUITEMINFOW MERGECOPY MERGEPAINT Metadatas metafile -mfapi mfc -mfidl -mfobjects mfplat -Mfsensorgroup -mftransform Mgmt mic midl mii -MIIM mindaro -Minimatch Minimizable MINIMIZEBOX MINIMIZEEND MINIMIZESTART miniz +MINMAXINFO Mip Miracast mjpg @@ -914,11 +895,10 @@ mlcfg mmc mmcexe MMdd -mmdeviceapi mmi mmsys -mmsystem mockapi +MODALFRAME MODESPRUNED MONITORENUMPROC MONITORINFO @@ -938,16 +918,16 @@ mpmc MRM MRT mru -mrw msc mscorlib +msctls msdata MSDL -msedge MSGFLT msiexec MSIFASTINSTALL MSIHANDLE +Msimg msiquery MSIRESTARTMANAGERCONTROL msixbundle @@ -959,6 +939,7 @@ msrc msstore mst msvcp +msvsmon MTND MULTIPLEUSE multizone @@ -989,53 +970,57 @@ NCPAINT NCRENDERING ndp NEEDDISPATCH -needinfo netcoreapp netcpl netframework netsetup netsh newcolor -newdev NEWDIALOGSTYLE NEWFILE newitem newpath newplus NEWPLUSCONTEXTMENU +NEWPLUSSHELLEXTENSIONWIN newrow newsgroups NIF -NLD NLog NLSTEXT +NMAKE NNN NOACTIVATE NOAGGREGATION NOASYNC +NOCLIP NOCLOSEPROCESS NOCOALESCE NOCOMM NOCONFIRMMKDIR NOCOPYBITS NOCOPYSECURITYATTRIBS +NOCRLF nodeca -nodoc NODRAWCAPTION NODRAWICON NOINHERITLAYOUT NOINTERFACE +NOINVERT NOLINKINFO NOMCX NOMINMAX NOMIRRORBITMAP NOMOVE +NONANTIALIASED nonclient +NONCLIENTMETRICSW NONELEVATED NONINFRINGEMENT nonstd NOOWNERZORDER NOPARENTNOTIFY +NOPREFIX NOREDIRECTIONBITMAP NOREDRAW NOREMOVE @@ -1048,33 +1033,34 @@ NORMALUSER NOSEARCH NOSENDCHANGING NOSIZE +NOTHOUSANDS +NOTICKS NOTIFICATIONSDLL NOTIFYICONDATA NOTIFYICONDATAW NOTIMPL -notlike NOTOPMOST NOTRACK NOTSRCCOPY NOTSRCERASE +NOTXORPEN NOZORDER NPH npmjs NResize -nrw nsunt NTAPI ntdll -ntfs NTSTATUS +NTSYSAPI +NULLCURSOR nullonfailure numberbox nwc -Objbase -objidl ocr Ocrsettings odbccp +OEMCONVERT officehubintl OFN ofs @@ -1084,30 +1070,31 @@ oldpath oldtheme oleaut OLECHAR -onebranch opencode OPENFILENAME opensource openxmlformats OPTIMIZEFORINVOKE ORAW -ori ORPHANEDDIALOGTITLE ORSCANS oss ostr +OSVERSIONINFO OSVERSIONINFOEX OSVERSIONINFOEXW +OSVERSIONINFOW osvi OUTOFCONTEXT outpin Outptr -outputtype outsettings OVERLAPPEDWINDOW overlaywindow Oversampling +OVERWRITEPROMPT OWNDC +OWNERDRAWFIXED Packagemanager PACL PAINTSTRUCT @@ -1119,7 +1106,6 @@ PARENTRELATIVEPARSING parray PARTIALCONFIRMATIONDIALOGTITLE PATCOPY -pathcch PATHMUSTEXIST PATINVERT PATPAINT @@ -1133,17 +1119,21 @@ pcelt pch pchast PCIDLIST +PCTSTR PCWSTR pdbs +PDEVMODE pdisp +PDLL pdo pdto pdtobj pdw Peb -pef PElems Pels +PELSHEIGHT +PELSWIDTH PERCEIVEDFLAG perfmon pesi @@ -1166,16 +1156,20 @@ pinvoke pipename PKBDLLHOOKSTRUCT plib -PLK ploc ploca plocm pluginsmodel +PMAGTRANSFORM PMSIHANDLE pnid +PNMLINK Pnp +POINTERID +POINTERUPDATE Popups POPUPWINDOW +POSITIONITEM POWERRENAMECONTEXTMENU powerrenameinput POWERRENAMETEST @@ -1199,7 +1193,6 @@ pptal ppv prc Prefixer -Preinstalled prependpath prevhost previewer @@ -1212,13 +1205,12 @@ prgms pri PRINTCLIENT printmanagement -privacystatement prm proactively PROCESSENTRY PROCESSKEY -processthreadsapi PROCESSTRACE +procmon PRODEXT PRODUCTVERSION Progman @@ -1226,10 +1218,9 @@ programdata projectname PROPBAG PROPERTYKEY -propkey -propsys PROPVARIANT propvarutil +PRTL prvpane psapi pscid @@ -1237,24 +1228,24 @@ PSECURITY psfgao psfi PSMODULEPATH -Psr psrm psrree pstatstg pstm -pstr +PStr pstream pstrm PSYSTEM psz ptb ptc +PTCHAR ptd PTOKEN PToy ptstr pui -pwa +PWAs pwcs PWSTR pwsz @@ -1270,15 +1261,18 @@ QUERYENDSESSION QUERYOPEN QUEUESYNC QUNS -raf RAII RAlt +randi Rasterize RAWINPUTDEVICE RAWINPUTHEADER +RAWMODE RAWPATH rbhid rclsid +RCZOOMIT +RDW READMODE READOBJECTS recents @@ -1287,7 +1281,6 @@ rectp RECTSOURCE recyclebin Redist -redistributable reencode reencoded REFCLSID @@ -1316,11 +1309,8 @@ remoteip Removelnk renamable RENAMEONCOLLISION -Renamer reparented reparenting -reparse -reportbug reportfileaccesses requery requerying @@ -1332,8 +1322,6 @@ RESIZETOFIT resmimetype RESOURCEID RESTORETOMAXIMIZED -restrictedcapabilities -restrictederrorinfo resultlist RETURNONLYFSDIRS RGBQUAD @@ -1348,7 +1336,6 @@ riid ringbuffer RKey RNumber -roadmap rop ROUNDSMALL rpcrt @@ -1359,23 +1346,17 @@ Rsp rstringalnum rstringalpha rstringdigit -Rstrtmgr RTB RTLREADING -ruleset runas rundll rungameid RUNLEVEL runtimeclass -runtimeobject runtimepack -runtimes ruuid rvm rwin -rwl -rwz sacl safeprojectname SAMEKEYPREVIOUSLYMAPPED @@ -1387,25 +1368,36 @@ SCID Scip scipbe Scode +SCREENFONTS screensaver screenshots scrollviewer -sddl +SDDL SDKDDK sdns searchterm SEARCHUI +SECONDARYDISPLAY secpol +SELCHANGE SENDCHANGE -sendinput sendvirtualinput serverside +SETBUDDYINT SETCONTEXT +SETCURSEL setcursor SETFOCUS SETFOREGROUND +SETHOTKEY SETICON +SETLOWPOWERACTIVE +SETPOWEROFFACTIVE +SETRANGE SETREDRAW +SETRULES +SETSCREENSAVEACTIVE +SETSTICKYKEYS SETTEXT SETTINGCHANGE SETTINGSCHANGED @@ -1413,36 +1405,31 @@ settingsheader settingshotkeycontrol setvariable SETWORKAREA -setzero sfgao SFGAOF +SHACF SHANDLE sharpkeys SHCNE SHCNF SHCONTF -shcore -shellapi +Shcore SHELLDETAILS SHELLDLL shellex SHELLEXECUTEINFO SHELLEXECUTEINFOW -shellscalingapi SHFILEINFO SHFILEOPSTRUCT SHGDN SHGDNF SHGFI shinfo -shldisp -shlobj shlwapi shmem SHNAMEMAPPING shobjidl SHORTCUTATLEAST -shortcutcontrol SHORTCUTMAXONEACTIONKEY SHORTCUTNOREPEATEDMODIFIER SHORTCUTONEACTIONKEY @@ -1454,6 +1441,7 @@ shortsplit showcolorname SHOWDEFAULT SHOWELEVATIONPROMPT +SHOWMAGNIFIEDCURSOR SHOWMAXIMIZED SHOWMINIMIZED SHOWMINNOACTIVE @@ -1471,7 +1459,6 @@ sigdn SIGNINGSCENARIO Signtool SINGLEKEY -singlekeyremapcontrol sipolicy SIZEBOX Sizename @@ -1480,6 +1467,7 @@ SIZENS SIZENWSE sizeread SIZEWE +SKEXP SKIPOWNPROCESS sku SLGP @@ -1509,7 +1497,6 @@ Srch SRCINVERT SRCPAINT SResize -srf srme srre srw @@ -1529,6 +1516,7 @@ STATICEDGE STATSTG stdafx STDAPI +stdc stdcpplatest STDMETHODCALLTYPE STDMETHODIMP @@ -1536,23 +1524,26 @@ STGC STGM STGMEDIUM sticpl +STICKYKEYS stl storelogo +stprintf streamjsonrpc STRINGIZE stringtable stringval Strm -Strmiids strret strsafe strutil +stscanf sttngs Stubless STYLECHANGED STYLECHANGING subkeys sublang +SUBMODULEUPDATE subquery Superbar sut @@ -1561,7 +1552,6 @@ SVGIn SVGIO svgz SVSI -SWC SWFO SWP SWRESTORE @@ -1583,8 +1573,8 @@ SYSKEYUP SYSLIB SYSMENU SYSTEMAPPS +SYSTEMMODAL SYSTEMTIME -tapp TApplication TApplied targ @@ -1595,10 +1585,19 @@ TARGETHEADER targetver taskkill taskschd -tchar +TCHAR +TCIF +TCITEM +TCN Tcollab tcs +tcscat +tcschr +tcscmp tcscpy +tcsdup +tcslen +tcsrchr TCustom tdbuild TDefault @@ -1609,18 +1608,20 @@ testprocess TEXCOORD TEXTEXTRACTOR TEXTINCLUDE +tfopen tgz themeresources THH THICKFRAME THISCOMPONENT THotkey -thumbcache TILEDWINDOW +TILLSON timedate timediff timeunion timeutil +TITLEBARINFO Titlecase tkcontrols tkconverters @@ -1631,26 +1632,24 @@ TMPVAR TNP Toolhelp toolkitconverters -Toolset toolwindow TOPDOWNDIB TOUCHEVENTF TOUCHINPUT -touchpad TRACEHANDLE tracelogging tracerpt +trackbar trafficmanager traies transicc TRAYMOUSEMESSAGE triaging -TRK trl trx tsa -Tsd TServer +tstoi TStr tweakme TWF @@ -1659,8 +1658,10 @@ TYPEKEYBOARD TYPEMOUSE TYPESHORTCUT UAC +UACUI UAL uap +UBR UCallback udit uefi @@ -1674,31 +1675,29 @@ ums uncompilable UNCPRIORITY UNDNAME +unhiding UNICODETEXT -uninstantiated -uniquifier Uniquifies unitconverter unittests -unknwn UNLEN UNORM -unregistering unremapped unvirtualized unwide +unzoom UOffset UOI Updatelayout +UPDATENOW +UPDATEREGISTRY +updown UPGRADINGPRODUCTCODE Uptool urld -urlmon Usb USEDEFAULT USEFILEATTRIBUTES -USERDATA -Userenv USESHOWWINDOW USESTDHANDLES USRDLL @@ -1714,9 +1713,9 @@ vcamp vcdl vcgtq VCINSTALLDIR -vcm Vcpkg VCRT +VCENTER vcruntime vcvars VDesktop @@ -1725,17 +1724,18 @@ vdupq VERBSONLY VERBW VERIFYCONTEXT -verrsrc VERSIONINFO +VERTRES +VERTSIZE VFT vget vgetq vid VIDCAP -videoconferencevirtualdriver VIDEOINFOHEADER viewmodel vih +VIRTKEY VIRTUALDESK VISEGRADRELAY visiblecolorformats @@ -1762,17 +1762,15 @@ vsonline vstemplate vstest VSTHRD +vstprintf VSTT vswhere Vtbl WANTMAPPINGHANDLE WANTPALM wbem -Wbemidl -wbemuuid WBounds Wca -wcautil WCE wcex WClass @@ -1780,6 +1778,7 @@ wcsicmp wcsncpy wcsnicmp WDA +wdm wdp wdupenv webbrowsers @@ -1787,51 +1786,38 @@ webcam webpage websites wekyb -Wevtapi wgpocpl WIC +wifi wil winapi -wincodec -Wincodecsdk +winappsdk wincolor -windef windir WINDOWCREATED WINDOWEDGE +WINDOWINFO WINDOWNAME WINDOWPLACEMENT WINDOWPOSCHANGED WINDOWPOSCHANGING -windowsapp WINDOWSBUILDNUMBER -Windowscodecs windowssearch windowssettings WINDOWSTYLES WINDOWSTYLESICON -windowsx -winerror WINEVENT -winevt -winexe -winforms -winfx winget wingetcreate Winhook WINL winlogon winmd -winmm -winnt +WINNT winres winrt winsdk -winsdkver -winspool winsta -winternl WINTHRESHOLD WINVER winxamlmanager @@ -1856,7 +1842,6 @@ WNDCLASSEXW WNDCLASSW WNDPROC wnode -workarounds WORKSPACESEDITOR WORKSPACESLAUNCHER WORKSPACESSNAPSHOTTOOL @@ -1878,14 +1863,12 @@ wrl wscui wsf wsh -wsl wstr wsz WTA WTNCA wtoi WTS -wtsapi WTSAT Wubi WVC @@ -1896,7 +1879,6 @@ XElement xfd XFile XIncrement -XLoc XNamespace Xoshiro XPels @@ -1921,4 +1903,7 @@ ZEROINIT zonable zoneset Zoneszonabletester +Zoomin +zoomit +ZOOMITX zzz diff --git a/.github/actions/spell-check/line_forbidden.patterns b/.github/actions/spell-check/line_forbidden.patterns index 8ddb666cd6ec..24483dd6f5de 100644 --- a/.github/actions/spell-check/line_forbidden.patterns +++ b/.github/actions/spell-check/line_forbidden.patterns @@ -1,119 +1,289 @@ # 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 +# Were you debugging using a framework with `fit()`? # If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test, -# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want -# to use this: +# you might not want to check in code where you skip all the other tests. #\bfit\( -# s.b. anymore +# Should be `HH:MM:SS` +\bHH:SS:MM\b + +# Should be `86400` (seconds in a standard day) +\b84600\b(?:.*\bday\b) + +# Should probably be `2006-01-02` (yyyy-mm-dd) +# Assuming that the time is being passed to https://go.dev/src/time/format.go +\b2006-02-01\b + +# Should probably be `YYYYMMDD` +\b[Yy]{4}[Dd]{2}[Mm]{2}(?!.*[Yy]{4}[Dd]{2}[Mm]{2}).*$ + +# Should be `a priori` or `and prior` +(?i)(? Don't use `can not` when you mean `cannot`. The only time you're likely to see `can not` written as separate words is when the word `can` happens to precede some other phrase that happens to start with `not`. +# > `Can't` is a contraction of `cannot`, and it's best suited for informal writing. +# > In formal writing and where contractions are frowned upon, use `cannot`. +# > It is possible to write `can not`, but you generally find it only as part of some other construction, such as `not only . . . but also.` +# - if you encounter such a case, add a pattern for that case to patterns.txt. +\b[Cc]an not\b + +# Do not use `(click) here` links +# For more information, see: +# * https://www.w3.org/QA/Tips/noClickHere +# * https://webaim.org/techniques/hypertext/link_text +# * https://granicus.com/blog/why-click-here-links-are-bad/ +# * https://heyoka.medium.com/dont-use-click-here-f32f445d1021 +(?i)(?:>|\[)(?:(?:click |)here|this(?=\]\([^\)]+:/)|link|(?:read |)more(?!|".*?") + +# #pragma lib +^\s*#pragma comment\(lib, ".*?"\) + +# languageHashTable +"\w+(?:-\w+|)"\s+=\s+@\(".*"\) + +# wikipedia +\b\w\w\.wikipedia\.org/wiki/[-\w%.#]+ + +# css fonts +\bfont-family:[^;}]+ + +# .github/policies/resourceManagement.yml +pattern: '.*' + +# tabs in c# +\$"\\t + +# Hexadecimal character pattern in code +\\x[0-9a-fA-F][0-9a-fA-F] + +# windows line breaks in strings +\\r\\n + +# power shell gallery website +\bpowershellgallery.com/[-_a-zA-Z0-9()=./%]* + +# 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"[abAB]+", ){3}L"[abAB]+" + +# hit-count: 1 file-count: 1 +# marker to ignore all code on line +^.*/\* #no-spell-check-line \*/.*$ + +# UnitTests +\[DataRow\(.*\)\] + +# AdditionalDependencies +.*< + +# the last line of mimetype="application/x-microsoft.net.object.bytearray.base64" things in .resx files +^\s*[-a-zA-Z=;:/0-9+]*[-a-zA-Z;:/0-9+][-a-zA-Z=;:/0-9+]*=$ + # Automatically suggested patterns -# hit-count: 3011 file-count: 842 + +# hit-count: 3715 file-count: 992 # IServiceProvider / isAThing -\b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b) +(?:\b|_)(?:(?:ns|)I|isA)(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b)) + +# hit-count: 404 file-count: 42 +# base64 encoded content, possibly wrapped in mime +(?:^|[\s=;:?])[-a-zA-Z=;:/0-9+]{50,}(?:[\s=;:?]|$) -# hit-count: 2239 file-count: 134 +# hit-count: 402 file-count: 160 # hex runs \b[0-9a-fA-F]{16,}\b -# hit-count: 1868 file-count: 1 -# sha-... -- uses a fancy capture -(\\?['"]|")[0-9a-f]{40,}\g{-1} +# hit-count: 337 file-count: 110 +# 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: 1100 file-count: 97 -# base64 encoded content, possibly wrapped in mime -(?:^|[\s=;:?])[-a-zA-Z=;:/0-9+]{50,}(?:[\s=;:?]|$) +# hit-count: 311 file-count: 43 +# D2D +D?2D(?!efault) -# hit-count: 426 file-count: 165 +# hit-count: 272 file-count: 75 # GitHub SHAs (markdown) (?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|) -# 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 +# hit-count: 146 file-count: 27 # version suffix v# (?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_])) -# hit-count: 209 file-count: 97 +# hit-count: 105 file-count: 103 # w3 \bw3\.org/[-0-9a-zA-Z/#.]+ -# hit-count: 137 file-count: 38 -# alternate markers if you run into latex and friends -(?]|\b)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{10,12}(?:\g{-1}|[<})>]) +# hit-count: 3 file-count: 2 +# css url wrappings +\burl\([^)]+\) -(?:L"[abAB]+", ){3}L"[abAB]+" +# hit-count: 3 file-count: 1 +# kubernetes crd patterns +^\s*pattern: .*$ -# hit-count: 1 file-count: 1 -# marker to ignore all code on line -^.*/\* #no-spell-check-line \*/.*$ +# hit-count: 3 file-count: 1 +# Lorem +# 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) +(?:(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*) -# UnitTests -\[DataRow\(.*\)\] +# hit-count: 3 file-count: 1 +# libraries +(?:\b|_)lib(?:re(?=office)|)(?!era[lt]|ero|erty|rar(?:i(?:an|es)|y))(?=[a-z]) -# D2D -D?2D +# hit-count: 2 file-count: 1 +# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there +# YouTube url +\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]* # hit-count: 1 file-count: 1 # GHSA GHSA(?:-[0-9a-z]{4}){3} +# hit-count: 1 file-count: 1 +# GitHub actions +\buses:\s+[-\w.]+/[-\w./]+@[-\w.]+ + # hit-count: 1 file-count: 1 # medium -\bmedium\.com/\@?[^/\s"]+/[-\w]+ +\bmedium\.com/@?[^/\s"]+/[-\w]+ # hit-count: 1 file-count: 1 -# kubectl.kubernetes.io/last-applied-configuration -"kubectl.kubernetes.io/last-applied-configuration": ".*" +# sha-... -- uses a fancy capture +(\\?['"]|")[0-9a-f]{40,}\g{-1} # hit-count: 1 file-count: 1 # tar arguments \b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+ -\bSecur32 - # Questionably acceptable forms of `in to` # Personally, I prefer `log into`, but people object # https://www.tprteaching.com/log-into-log-in-to-login/ -\b(?:[Ll]og|[Ss]ign) in to\b +\b(?:(?:[Ll]og(?:g(?=[a-z])|)|[Ss]ign)(?:ed|ing)?) in to\b # to opt in \bto opt in\b # acceptable duplicates # ls directory listings -[-bcdlpsw](?:[-r][-w][-Ssx]){3}\s+\d+\s+\S+\s+\S+\s+\d+\s+ +[-bcdlpsw](?:[-r][-w][-SsTtx]){3}[\.+*]?\s+\d+\s+\S+\s+\S+\s+[.\d]+(?:[KMGT]|)\s+ # mount \bmount\s+-t\s+(\w+)\s+\g{-1}\b # C types and repeated CSS values -\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 +\s(auto|buffalo|center|div|inherit|long|LONG|none|normal|solid|thin|transparent|very)(?: \g{-1})+\s +# C enum and struct +\b(?:enum|struct)\s+(\w+)\s+\g{-1}\b # go templates \s(\w+)\s+\g{-1}\s+\`(?:graphql|inject|json|yaml): # doxygen / javadoc / .net -(?:[\\@](?:brief|groupname|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+static|\s+override|\s+readonly)*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s +(?:[\\@](?:brief|defgroup|groupname|link|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+(?:static|override|readonly|required|virtual))*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s + +# macOS file path +(?:Contents\W+|(?!iOS)/)MacOS\b + +# Python package registry has incorrect spelling for macOS / Mac OS X +"Operating System :: MacOS :: MacOS X" + +# "company" in Germany +\bGmbH\b + +# IntelliJ +\bIntelliJ\b # Commit message -- Signed-off-by and friends ^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$ @@ -190,3 +231,7 @@ _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING # ignore long runs of a single character: \b([A-Za-z])\g{-1}{3,}\b + +# ZoomIt menu items with accelerator keys +E&xit +St&yle diff --git a/.github/actions/spell-check/reject.txt b/.github/actions/spell-check/reject.txt index e5e4c3eef82e..5cc86ef80c91 100644 --- a/.github/actions/spell-check/reject.txt +++ b/.github/actions/spell-check/reject.txt @@ -3,9 +3,11 @@ benefitting occurences? ^dependan.* +^diables?$ ^oer$ Sorce ^[Ss]pae.* +^Teh$ ^untill$ ^untilling$ ^wether.* diff --git a/.github/workflows/spelling2.yml b/.github/workflows/spelling2.yml index b550f8986bf4..e79708399f37 100644 --- a/.github/workflows/spelling2.yml +++ b/.github/workflows/spelling2.yml @@ -34,14 +34,14 @@ name: Spell checking # # For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key -# Sarif reporting +# SARIF reporting # -# Access to Sarif reports is generally restricted (by GitHub) to members of the repository. +# 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 +# For information on the feature, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-SARIF-output # Minimal workflow structure: # @@ -60,23 +60,23 @@ name: Spell checking on: push: branches: - - "**" + - "**" tags-ignore: - - "**" + - "**" pull_request_target: branches: - - "**" + - "**" types: - - 'opened' - - 'reopened' - - 'synchronize' + - "opened" + - "reopened" + - "synchronize" issue_comment: types: - - 'created' + - "created" jobs: spelling: - name: Spell checking + name: Check Spelling permissions: contents: read pull-requests: read @@ -91,52 +91,59 @@ jobs: # note: If you use only_check_changed_files, you do not want cancel-in-progress cancel-in-progress: true steps: - - name: check-spelling - id: spelling - uses: check-spelling/check-spelling@v0.0.22 - with: - config: .github/actions/spell-check - suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }} - checkout: true - check_file_names: 1 - spell_check_this: microsoft/PowerToys@main - post_comment: 0 - use_magic_file: 1 - 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: - cspell:aws/aws.txt - cspell:cpp/src/compiler-clang-attributes.txt - cspell:cpp/src/compiler-msvc.txt - cspell:cpp/src/lang-keywords.txt - cspell:cpp/src/stdlib-c.txt - cspell:cpp/src/stdlib-cmath.txt - cspell:cpp/src/stdlib-cpp.txt - cspell:csharp/csharp.txt - cspell:css/dict/css.txt - cspell:django/dict/django.txt - cspell:dotnet/dict/dotnet.txt - cspell:filetypes/filetypes.txt - cspell:fullstack/dict/fullstack.txt - cspell:golang/dict/go.txt - cspell:html/dict/html.txt - cspell:java/src/java.txt - cspell:java/src/java-terms.txt - cspell:k8s/dict/k8s.txt - cspell:lorem-ipsum/dictionary.txt - cspell:monkeyc/src/monkeyc_keywords.txt - cspell:node/dict/node.txt - cspell:php/dict/php.txt - cspell:powershell/dict/powershell.txt - cspell:python/src/common/extra.txt - cspell:python/src/python/python.txt - cspell:python/src/python/python-lib.txt - cspell:scala/dict/scala.txt - cspell:software-terms/dict/softwareTerms.txt - cspell:swift/src/swift.txt - cspell:typescript/dict/typescript.txt + - name: check-spelling + id: spelling + uses: check-spelling/check-spelling@v0.0.24 + with: + config: .github/actions/spell-check + suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }} + checkout: true + check_file_names: 1 + spell_check_this: microsoft/PowerToys@main + post_comment: 0 + use_magic_file: 1 + report-timing: 1 + 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,unclosed-block-ignore-begin,unclosed-block-ignore-end + experimental_apply_changes_via_bot: 1 + use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }} + check_extra_dictionaries: "" + dictionary_source_prefixes: > + { + "cspell": "https://raw.githubusercontent.com/check-spelling/cspell-dicts/v20241114/dictionaries/" + } + extra_dictionaries: | + cspell:software-terms/softwareTerms.txt + cspell:cpp/stdlib-cpp.txt + cspell:filetypes/filetypes.txt + cspell:cpp/stdlib-c.txt + cspell:lorem-ipsum/dictionary.txt + cspell:python/python/python-lib.txt + cspell:php/php.txt + cspell:fullstack/fullstack.txt + cspell:dotnet/dotnet.txt + cspell:swift/swift.txt + cspell:node/node.txt + cspell:dart/dart.txt + cspell:django/django.txt + cspell:python/python/python.txt + cspell:powershell/powershell.txt + cspell:npm/npm.txt + cspell:golang/go.txt + cspell:cpp/compiler-msvc.txt + cspell:csharp/csharp.txt + cspell:html/html.txt + cspell:java/java.txt + cspell:aws/aws.txt + cspell:typescript/typescript.txt + cspell:cpp/lang-keywords.txt + cspell:python/common/extra.txt + cspell:scala/scala.txt + cspell:shell/shell-all-words.txt + cspell:css/css.txt + cspell:r/r.txt + cspell:java/java-terms.txt + cspell:cpp/stdlib-cerrno.txt + cspell:k8s/k8s.txt comment-push: name: Report (Push) @@ -144,16 +151,17 @@ jobs: runs-on: ubuntu-latest needs: spelling permissions: + actions: read contents: write if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push' steps: - - name: comment - uses: check-spelling/check-spelling@v0.0.22 - with: - config: .github/actions/spell-check - checkout: true - spell_check_this: microsoft/PowerToys@main - task: ${{ needs.spelling.outputs.followup }} + - name: comment + uses: check-spelling/check-spelling@v0.0.24 + with: + config: .github/actions/spell-check + checkout: true + spell_check_this: microsoft/PowerToys@main + task: ${{ needs.spelling.outputs.followup }} comment-pr: name: Report (PR) @@ -161,18 +169,19 @@ jobs: runs-on: ubuntu-latest needs: spelling permissions: + actions: read contents: read pull-requests: write if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request') steps: - - name: comment - uses: check-spelling/check-spelling@v0.0.22 - with: - config: .github/actions/spell-check - checkout: true - spell_check_this: check-spelling/spell-check-this@prerelease - task: ${{ needs.spelling.outputs.followup }} - experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }} + - name: comment + uses: check-spelling/check-spelling@v0.0.24 + with: + config: .github/actions/spell-check + checkout: true + spell_check_this: check-spelling/spell-check-this@prerelease + task: ${{ needs.spelling.outputs.followup }} + experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }} update: name: Update PR @@ -182,18 +191,19 @@ jobs: 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') + github.repository_owner != 'microsoft' && + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + contains(github.event.comment.body, '@check-spelling-bot apply') && + contains(github.event.comment.body, 'https://') }} 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 }}" + - name: apply spelling updates + uses: check-spelling/check-spelling@v0.0.24 + with: + experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }} + checkout: true + ssh_key: "${{ secrets.CHECK_SPELLING }}" diff --git a/.pipelines/ESRPSigning_core.json b/.pipelines/ESRPSigning_core.json index 5319bdc55fd9..13181ebfd1bc 100644 --- a/.pipelines/ESRPSigning_core.json +++ b/.pipelines/ESRPSigning_core.json @@ -17,7 +17,6 @@ "PowerToys.FilePreviewCommon.dll", "PowerToys.Interop.dll", "Tools\\PowerToys.BugReportTool.exe", - "WebcamReportTool\\PowerToys.WebcamReportTool.exe", "StylesReportTool\\PowerToys.StylesReportTool.exe", "Telemetry.dll", "PowerToys.ManagedTelemetry.dll", @@ -181,6 +180,7 @@ "WinUI3Apps\\PowerToys.NewPlus.ShellExtension.dll", "WinUI3Apps\\NewPlusPackage.msix", + "WinUI3Apps\\PowerToys.NewPlus.ShellExtension.win10.dll", "PowerAccent.Core.dll", "PowerToys.PowerAccent.dll", @@ -201,6 +201,7 @@ "PowerToys.WorkspacesLauncherUI.exe", "PowerToys.WorkspacesLauncherUI.dll", "PowerToys.WorkspacesModuleInterface.dll", + "PowerToys.WorkspacesCsharpLibrary.dll", "WinUI3Apps\\PowerToys.RegistryPreviewExt.dll", "WinUI3Apps\\PowerToys.RegistryPreviewUILib.dll", @@ -210,10 +211,9 @@ "PowerToys.ShortcutGuide.exe", "PowerToys.ShortcutGuideModuleInterface.dll", - "PowerToys.VideoConferenceModule.dll", - "PowerToys.VideoConferenceProxyFilter_x86.dll", - "PowerToys.VideoConferenceProxyFilter_x64.dll", - "PowerToys.VideoConferenceProxyFilter_arm64.dll", + "PowerToys.ZoomIt.exe", + "PowerToys.ZoomItModuleInterface.dll", + "PowerToys.ZoomItSettingsInterop.dll", "WinUI3Apps\\PowerToys.Settings.dll", "WinUI3Apps\\PowerToys.Settings.exe" @@ -325,6 +325,7 @@ "WinUI3Apps\\TestableIO.System.IO.Abstractions.dll", "TestableIO.System.IO.Abstractions.Wrappers.dll", "WinUI3Apps\\TestableIO.System.IO.Abstractions.Wrappers.dll", + "WinUI3Apps\\OpenAI.dll", "ColorCode.Core.dll", "ColorCode.UWP.dll", "UnitsNet.dll", diff --git a/.pipelines/ESRPSigning_vcm.json b/.pipelines/ESRPSigning_vcm.json deleted file mode 100644 index e9f2309cc413..000000000000 --- a/.pipelines/ESRPSigning_vcm.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "Version": "1.0.0", - "UseMinimatch": false, - "SignBatches": [ - { - "MatchedPath": [ - "PowerToys.VideoConferenceProxyFilter_x86.dll" - ], - "SigningInfo": { - "Operations": [ - { - "KeyCode": "CP-230012", - "OperationSetCode": "SigntoolSign", - "Parameters": [ - { - "parameterName": "OpusName", - "parameterValue": "Microsoft" - }, - { - "parameterName": "OpusInfo", - "parameterValue": "http://www.microsoft.com" - }, - { - "parameterName": "FileDigest", - "parameterValue": "/fd \"SHA256\"" - }, - { - "parameterName": "PageHash", - "parameterValue": "/NPH" - }, - { - "parameterName": "TimeStamp", - "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" - } - ], - "ToolName": "sign", - "ToolVersion": "1.0" - }, - { - "KeyCode": "CP-230012", - "OperationSetCode": "SigntoolVerify", - "Parameters": [], - "ToolName": "sign", - "ToolVersion": "1.0" - } - ] - } - } - ] -} diff --git a/.pipelines/UpdateVersions.ps1 b/.pipelines/UpdateVersions.ps1 new file mode 100644 index 000000000000..c19dfb5dec07 --- /dev/null +++ b/.pipelines/UpdateVersions.ps1 @@ -0,0 +1,130 @@ +Param( + # Using the default value of 1.6 for winAppSdkVersionNumber and useExperimentalVersion as false + [Parameter(Mandatory=$False,Position=1)] + [string]$winAppSdkVersionNumber = "1.6", + + # When the pipeline calls the PS1 file, the passed parameters are converted to string type + [Parameter(Mandatory=$False,Position=2)] + [boolean]$useExperimentalVersion = $False +) + +function Update-NugetConfig { + param ( + [string]$filePath = "nuget.config" + ) + + Write-Host "Updating nuget.config file" + [xml]$xml = Get-Content -Path $filePath + + # Add localpackages source into nuget.config + $packageSourcesNode = $xml.configuration.packageSources + $addNode = $xml.CreateElement("add") + $addNode.SetAttribute("key", "localpackages") + $addNode.SetAttribute("value", "localpackages") + $packageSourcesNode.AppendChild($addNode) | Out-Null + + # Remove tag and its content + $packageSourceMappingNode = $xml.configuration.packageSourceMapping + if ($packageSourceMappingNode) { + $xml.configuration.RemoveChild($packageSourceMappingNode) | Out-Null + } + + # print nuget.config after modification + $xml.OuterXml + # Save the modified nuget.config file + $xml.Save($filePath) +} + +$sourceLink = "https://microsoft.pkgs.visualstudio.com/ProjectReunion/_packaging/Project.Reunion.nuget.internal/nuget/v3/index.json" + +# Execute nuget list and capture the output +if ($useExperimentalVersion) { + # The nuget list for experimental versions will cost more time + # So, we will not use -AllVersions to wast time + # But it can only get the latest experimental version + Write-Host "Fetching WindowsAppSDK with experimental versions" + $nugetOutput = nuget list Microsoft.WindowsAppSDK ` + -Source $sourceLink ` + -Prerelease + # Filter versions based on the specified version prefix + $escapedVersionNumber = [regex]::Escape($winAppSdkVersionNumber) + $filteredVersions = $nugetOutput | Where-Object { $_ -match "Microsoft.WindowsAppSDK $escapedVersionNumber\." } + $latestVersions = $filteredVersions +} else { + Write-Host "Fetching stable WindowsAppSDK versions for $winAppSdkVersionNumber" + $nugetOutput = nuget list Microsoft.WindowsAppSDK ` + -Source $sourceLink ` + -AllVersions + # Filter versions based on the specified version prefix + $escapedVersionNumber = [regex]::Escape($winAppSdkVersionNumber) + $filteredVersions = $nugetOutput | Where-Object { $_ -match "Microsoft.WindowsAppSDK $escapedVersionNumber\." } + $latestVersions = $filteredVersions | Sort-Object { [version]($_ -split ' ')[1] } -Descending | Select-Object -First 1 +} + +Write-Host "Latest versions found: $latestVersions" +# Extract the latest version number from the output +$latestVersion = $latestVersions -split "`n" | ` + Select-String -Pattern 'Microsoft.WindowsAppSDK\s*([0-9]+\.[0-9]+\.[0-9]+-*[a-zA-Z0-9]*)' | ` + ForEach-Object { $_.Matches[0].Groups[1].Value } | ` + Sort-Object -Descending | ` + Select-Object -First 1 + +if ($latestVersion) { + $WinAppSDKVersion = $latestVersion + Write-Host "Extracted version: $WinAppSDKVersion" + Write-Host "##vso[task.setvariable variable=WinAppSDKVersion]$WinAppSDKVersion" +} else { + Write-Host "Failed to extract version number from nuget list output" + exit 1 +} + +# Update packages.config files +Get-ChildItem -Recurse packages.config | ForEach-Object { + $content = Get-Content $_.FullName -Raw + if ($content -match 'package id="Microsoft.WindowsAppSDK"') { + $newVersionString = 'package id="Microsoft.WindowsAppSDK" version="' + $WinAppSDKVersion + '"' + $oldVersionString = 'package id="Microsoft.WindowsAppSDK" version="[-.0-9a-zA-Z]*"' + $content = $content -replace $oldVersionString, $newVersionString + Set-Content -Path $_.FullName -Value $content + Write-Host "Modified " $_.FullName + } +} + +# Update Directory.Packages.props file +$propsFile = "Directory.Packages.props" +if (Test-Path $propsFile) { + $content = Get-Content $propsFile -Raw + if ($content -match '' + $oldVersionString = '' + $content = $content -replace $oldVersionString, $newVersionString + Set-Content -Path $propsFile -Value $content + Write-Host "Modified " $propsFile + } +} + +# Update .vcxproj files +Get-ChildItem -Recurse *.vcxproj | ForEach-Object { + $content = Get-Content $_.FullName -Raw + if ($content -match '\\Microsoft.WindowsAppSDK.') { + $newVersionString = '\Microsoft.WindowsAppSDK.' + $WinAppSDKVersion + '\' + $oldVersionString = '\\Microsoft.WindowsAppSDK.[-.0-9a-zA-Z]*\\' + $content = $content -replace $oldVersionString, $newVersionString + Set-Content -Path $_.FullName -Value $content + Write-Host "Modified " $_.FullName + } +} + +# Update .csproj files +Get-ChildItem -Recurse *.csproj | ForEach-Object { + $content = Get-Content $_.FullName -Raw + if ($content -match 'PackageReference Include="Microsoft.WindowsAppSDK"') { + $newVersionString = 'PackageReference Include="Microsoft.WindowsAppSDK" Version="'+ $WinAppSDKVersion + '"' + $oldVersionString = 'PackageReference Include="Microsoft.WindowsAppSDK" Version="[-.0-9a-zA-Z]*"' + $content = $content -replace $oldVersionString, $newVersionString + Set-Content -Path $_.FullName -Value $content + Write-Host "Modified " $_.FullName + } +} + +Update-NugetConfig diff --git a/.pipelines/applyXamlStyling.ps1 b/.pipelines/applyXamlStyling.ps1 index e47edd0c0fa8..7cb7b4a4b0ff 100644 --- a/.pipelines/applyXamlStyling.ps1 +++ b/.pipelines/applyXamlStyling.ps1 @@ -97,7 +97,7 @@ if (-not $Passive) if ($files.count -gt 0) { - dotnet tool run xstyler -c "$PSScriptRoot\..\Settings.XamlStyler" -f $files + dotnet tool run xstyler -c "$PSScriptRoot\..\src\Settings.XamlStyler" -f $files } else { @@ -111,7 +111,7 @@ else if ($files.count -gt 0) { - dotnet tool run xstyler -p -c "$PSScriptRoot\..\Settings.XamlStyler" -f $files + dotnet tool run xstyler -p -c "$PSScriptRoot\..\src\Settings.XamlStyler" -f $files if ($lastExitCode -eq 1) { diff --git a/.pipelines/loc/loc.yml b/.pipelines/loc/loc.yml index 2087e300eaf1..8d582c48305c 100644 --- a/.pipelines/loc/loc.yml +++ b/.pipelines/loc/loc.yml @@ -32,9 +32,9 @@ steps: TDBuildServiceConnection: $(TouchdownServiceConnection) authType: SubjectNameIssuer resourceFilePath: | - **\Resources.resx - **\Resource.resx - **\Resources.resw + src\**\Resources.resx + src\**\Resource.resx + src\**\Resources.resw outputDirectoryRoot: LocOutput appendRelativeDir: true pseudoSetting: Included diff --git a/.pipelines/v2/ci-test-with-canary-webview2.yml b/.pipelines/v2/ci-test-with-canary-webview2.yml new file mode 100644 index 000000000000..01f0454186bd --- /dev/null +++ b/.pipelines/v2/ci-test-with-canary-webview2.yml @@ -0,0 +1,42 @@ +trigger: none +pr: none +schedules: + - cron: "0 0 * * *" # every day at midnight + displayName: "Daily midnight Build" + branches: + include: + - main + always: false # only run if there's code changes! + +name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) + +parameters: + - name: buildPlatforms + type: object + default: + - x64 + - arm64 + - name: enableMsBuildCaching + type: boolean + displayName: "Enable MSBuild Caching" + default: false + - name: runTests + type: boolean + displayName: "Run Tests" + default: true + - name: useVSPreview + type: boolean + displayName: "Build Using Visual Studio Preview" + default: false + - name: useLatestWebView2 + type: boolean + default: false + +extends: + template: templates/pipeline-ci-build.yml + parameters: + buildPlatforms: ${{ parameters.buildPlatforms }} + enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }} + runTests: ${{ parameters.runTests }} + useVSPreview: ${{ parameters.useVSPreview }} + useLatestWebView2: ${{ parameters.useLatestWebView2 }} diff --git a/.pipelines/v2/ci-using-the-latest-winappsdk.yml b/.pipelines/v2/ci-using-the-latest-winappsdk.yml new file mode 100644 index 000000000000..cc9f00f80d14 --- /dev/null +++ b/.pipelines/v2/ci-using-the-latest-winappsdk.yml @@ -0,0 +1,50 @@ +trigger: none +pr: none +schedules: + - cron: "0 0 * * *" # every day at midnight + displayName: "Daily midnight Build" + branches: + include: + - main + always: false # only run if there's code changes! + +name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) + +parameters: + - name: buildPlatforms + type: object + default: + - x64 + - arm64 + - name: enableMsBuildCaching + type: boolean + displayName: "Enable MSBuild Caching" + default: false + - name: runTests + type: boolean + displayName: "Run Tests" + default: true + - name: useVSPreview + type: boolean + displayName: "Build Using Visual Studio Preview" + default: false + - name: useLatestWinAppSDK + type: boolean + default: true + - name: winAppSDKVersionNumber + type: string + default: 1.6 + - name: useExperimentalVersion + type: boolean + default: false + +extends: + template: templates/pipeline-ci-build.yml + parameters: + buildPlatforms: ${{ parameters.buildPlatforms }} + enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }} + runTests: ${{ parameters.runTests }} + useVSPreview: ${{ parameters.useVSPreview }} + useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }} + winAppSDKVersionNumber: ${{ parameters.winAppSDKVersionNumber }} + useExperimentalVersion: ${{ parameters.useExperimentalVersion }} diff --git a/.pipelines/v2/oneFuzz.yml b/.pipelines/v2/oneFuzz.yml new file mode 100644 index 000000000000..2bcbf360503b --- /dev/null +++ b/.pipelines/v2/oneFuzz.yml @@ -0,0 +1,55 @@ +pr: none +trigger: none + +schedules: + - cron: "0 0 * * 1" + displayName: Weekly fuzzing submission + branches: + include: + - main + always: true +name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) + +parameters: + - name: platform + type: string + default: x64 # for fuzzing, we only use x64 for now + - name: enableMsBuildCaching + type: boolean + displayName: "Enable MSBuild Caching" + default: false + - name: useVSPreview + type: boolean + displayName: "Build Using Visual Studio Preview" + default: false + +stages: + - stage: Build_${{ parameters.platform }} + displayName: Build ${{ parameters.platform }} + jobs: + - template: templates/job-build-project.yml + parameters: + pool: + ${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}: + name: SHINE-INT-L + ${{ else }}: + name: SHINE-OSS-L + ${{ if eq(parameters.useVSPreview, true) }}: + demands: ImageOverride -equals SHINE-VS17-Preview + buildPlatforms: + - ${{ parameters.platform }} + buildConfigurations: [Release] + enablePackageCaching: true + enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }} + runTests: true + useVSPreview: ${{ parameters.useVSPreview }} + + - stage: OneFuzz + displayName: Fuzz ${{ parameters.platform }} + dependsOn: + - Build_${{parameters.platform}} + jobs: + - template: templates/job-fuzz.yml + parameters: + platform: ${{ parameters.platform }} + configuration: Release diff --git a/.pipelines/v2/templates/job-build-project.yml b/.pipelines/v2/templates/job-build-project.yml index 1933b74e8de9..5a3b787ede41 100644 --- a/.pipelines/v2/templates/job-build-project.yml +++ b/.pipelines/v2/templates/job-build-project.yml @@ -56,6 +56,15 @@ parameters: - name: versionNumber type: string default: '0.0.1' + - name: useLatestWinAppSDK + type: boolean + default: false + - name: winAppSDKVersionNumber + type: string + default: 1.6 + - name: useExperimentalVersion + type: boolean + default: false - name: csProjectsToPublish type: object default: @@ -102,6 +111,10 @@ jobs: ${{ else }}: MSBuildMainBuildTargets: Build ${{ insert }}: ${{ parameters.variables }} + ${{ if eq(parameters.useLatestWinAppSDK, true) }}: + RestoreAdditionalProjectSourcesArg: '/p:RestoreAdditionalProjectSources="$(Build.SourcesDirectory)\localpackages\NugetPackages"' + ${{ else }}: + RestoreAdditionalProjectSourcesArg: '' displayName: Build timeoutInMinutes: 240 cancelTimeoutInMinutes: 1 @@ -134,6 +147,11 @@ jobs: sdk: true version: '6.0' + - template: steps-ensure-dotnet-version.yml + parameters: + sdk: true + version: '8.0' + - template: steps-ensure-dotnet-version.yml parameters: sdk: true @@ -154,7 +172,6 @@ jobs: - pwsh: |- & '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\PowerToys.sln' & '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\tools\BugReportTool\BugReportTool.sln' - & '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\tools\WebcamReportTool\WebcamReportTool.sln' & '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\tools\StylesReportTool\StylesReportTool.sln' & '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\installer\PowerToysSetup.sln' displayName: Verify ARM64 configurations @@ -177,8 +194,15 @@ jobs: "packages.config" | "$(Agent.OS)" "packages.config" path: packages - - - template: .\steps-restore-nuget.yml + + - ${{ if eq(parameters.useLatestWinAppSDK, true)}}: + - template: .\steps-update-winappsdk-and-restore-nuget.yml + parameters: + versionNumber: ${{ parameters.winAppSDKVersionNumber }} + useExperimentalVersion: ${{ parameters.useExperimentalVersion }} + + - ${{ if eq(parameters.useLatestWinAppSDK, false)}}: + - template: .\steps-restore-nuget.yml - pwsh: |- & "$(build.sourcesdirectory)\.pipelines\verifyAndSetLatestVCToolsVersion.ps1" @@ -209,6 +233,7 @@ jobs: ${{ parameters.additionalBuildOptions }} $(MSBuildCacheParameters) /t:$(MSBuildMainBuildTargets) + $(RestoreAdditionalProjectSourcesArg) platform: $(BuildPlatform) configuration: $(BuildConfiguration) msbuildArchitecture: x64 @@ -233,10 +258,11 @@ jobs: inputs: solution: '**\HostsUILib.csproj' vsVersion: 17.0 - ${{ if eq(parameters.useVSPreview, true) }}: - msbuildArgs: /p:CIBuild=true;NoBuild=true -t:pack /bl:$(LogOutputDirectory)\build-hosts.binlog /p:NoWarn=NU5104 - ${{ else }}: - msbuildArgs: /p:CIBuild=true;NoBuild=true -t:pack /bl:$(LogOutputDirectory)\build-hosts.binlog + msbuildArgs: >- + /p:CIBuild=true;NoBuild=true -t:pack + /bl:$(LogOutputDirectory)\build-hosts.binlog + /p:NoWarn=NU5104 + $(RestoreAdditionalProjectSourcesArg) configuration: $(BuildConfiguration) msbuildArchitecture: x64 maximumCpuCount: true @@ -249,10 +275,11 @@ jobs: inputs: solution: '**\EnvironmentVariablesUILib.csproj' vsVersion: 17.0 - ${{ if eq(parameters.useVSPreview, true) }}: - msbuildArgs: /p:CIBuild=true;NoBuild=true -t:pack /bl:$(LogOutputDirectory)\build-env-var-editor.binlog /p:NoWarn=NU5104 - ${{ else }}: - msbuildArgs: /p:CIBuild=true;NoBuild=true -t:pack /bl:$(LogOutputDirectory)\build-env-var-editor.binlog + msbuildArgs: >- + /p:CIBuild=true;NoBuild=true -t:pack + /bl:$(LogOutputDirectory)\build-env-var-editor.binlog + /p:NoWarn=NU5104 + $(RestoreAdditionalProjectSourcesArg) configuration: $(BuildConfiguration) msbuildArchitecture: x64 maximumCpuCount: true @@ -265,10 +292,11 @@ jobs: inputs: solution: '**\RegistryPreviewUILib.csproj' vsVersion: 17.0 - ${{ if eq(parameters.useVSPreview, true) }}: - msbuildArgs: /p:CIBuild=true;NoBuild=true -t:pack /bl:$(LogOutputDirectory)\build-registry-preview.binlog /p:NoWarn=NU5104 - ${{ else }}: - msbuildArgs: /p:CIBuild=true;NoBuild=true -t:pack /bl:$(LogOutputDirectory)\build-registry-preview.binlog + msbuildArgs: >- + /p:CIBuild=true;NoBuild=true -t:pack + /bl:$(LogOutputDirectory)\build-registry-preview.binlog + /p:NoWarn=NU5104 + $(RestoreAdditionalProjectSourcesArg) configuration: $(BuildConfiguration) msbuildArchitecture: x64 maximumCpuCount: true @@ -323,26 +351,7 @@ jobs: /bl:$(LogOutputDirectory)\build-bug-report.binlog ${{ parameters.additionalBuildOptions }} $(MSBuildCacheParameters) - platform: $(BuildPlatform) - configuration: $(BuildConfiguration) - msbuildArchitecture: x64 - maximumCpuCount: true - ${{ if eq(parameters.enableMsBuildCaching, true) }}: - env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - - - task: VSBuild@1 - displayName: Build WebcamReportTool - inputs: - solution: '**/tools/WebcamReportTool/WebcamReportTool.sln' - vsVersion: 17.0 - msbuildArgs: >- - -restore -graph - /p:RestorePackagesConfig=true - /p:CIBuild=true - /bl:$(LogOutputDirectory)\build-webcam-report.binlog - ${{ parameters.additionalBuildOptions }} - $(MSBuildCacheParameters) + $(RestoreAdditionalProjectSourcesArg) platform: $(BuildPlatform) configuration: $(BuildConfiguration) msbuildArchitecture: x64 @@ -363,6 +372,7 @@ jobs: /bl:$(LogOutputDirectory)\build-styles-report.binlog ${{ parameters.additionalBuildOptions }} $(MSBuildCacheParameters) + $(RestoreAdditionalProjectSourcesArg) platform: $(BuildPlatform) configuration: $(BuildConfiguration) msbuildArchitecture: x64 @@ -385,6 +395,7 @@ jobs: /p:PowerToysRoot=$(Build.SourcesDirectory) /p:PublishProfile=InstallationPublishProfile.pubxml /bl:$(LogOutputDirectory)\publish-${{ join('_',split(project, '/')) }}.binlog + $(RestoreAdditionalProjectSourcesArg) platform: $(BuildPlatform) configuration: $(BuildConfiguration) msbuildArchitecture: x64 @@ -414,9 +425,11 @@ jobs: & '.pipelines/verifyPossibleAssetConflicts.ps1' -targetDir '$(build.sourcesdirectory)\$(BuildPlatform)\$(BuildConfiguration)\WinUI3Apps' displayName: Audit WinAppSDK applications path asset conflicts - - pwsh: |- - & '.pipelines/verifyNoticeMdAgainstNugetPackages.ps1' -path '$(build.sourcesdirectory)\' - displayName: Verify NOTICE.md and NuGet packages match + # To streamline the pipeline and prevent errors, skip this step during compatibility tests with the latest WinAppSDK. + - ${{ if eq(parameters.useLatestWinAppSDK, false) }}: + - pwsh: |- + & '.pipelines/verifyNoticeMdAgainstNugetPackages.ps1' -path '$(build.sourcesdirectory)\' + displayName: Verify NOTICE.md and NuGet packages match - ${{ if eq(parameters.runTests, true) }}: # Publish test results which ran in MSBuild @@ -449,7 +462,7 @@ jobs: displayName: Sign Core PowerToys signingIdentity: ${{ parameters.signingIdentity }} inputs: - FolderPath: '$(BuildPlatform)/$(BuildConfiguration)' # Video conf uses x86 and x64. + FolderPath: '$(BuildPlatform)/$(BuildConfiguration)' signType: batchSigning batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_core.json' ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml' @@ -464,16 +477,6 @@ jobs: batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_DSC.json' ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml' - - template: steps-esrp-signing.yml - parameters: - displayName: Sign x86 DirectShow VCM - signingIdentity: ${{ parameters.signingIdentity }} - inputs: - FolderPath: 'x86/$(BuildConfiguration)' # Video conf uses x86 and x64. - signType: batchSigning - batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_vcm.json' - ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml' - - template: steps-build-installer.yml parameters: codeSign: ${{ parameters.codeSign }} diff --git a/.pipelines/v2/templates/job-fuzz.yml b/.pipelines/v2/templates/job-fuzz.yml new file mode 100644 index 000000000000..b4e380194e65 --- /dev/null +++ b/.pipelines/v2/templates/job-fuzz.yml @@ -0,0 +1,36 @@ +parameters: + - name: configuration + type: string + default: "Release" + - name: platform + type: string + default: "" + - name: inputArtifactStem + type: string + default: "" + +jobs: + - job: OneFuzz + pool: + vmImage: windows-2022 + variables: + ArtifactName: build-${{ parameters.platform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }} + steps: + - checkout: self + submodules: false + clean: true + fetchDepth: 1 + fetchTags: false + + - download: current + displayName: Download artifacts + artifact: $(ArtifactName) + patterns: |- + **/tests/*.FuzzTests/** + + - task: onefuzz-task@0 + inputs: + onefuzzOSes: Windows + env: + onefuzzDropDirectory: $(Pipeline.Workspace)\$(ArtifactName)\x64\Release\x64\Release\tests + SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/.pipelines/v2/templates/job-test-project.yml b/.pipelines/v2/templates/job-test-project.yml index 212dbeccd882..0bf4641e429f 100644 --- a/.pipelines/v2/templates/job-test-project.yml +++ b/.pipelines/v2/templates/job-test-project.yml @@ -8,6 +8,9 @@ parameters: - name: inputArtifactStem type: string default: "" + - name: useLatestWebView2 + type: boolean + default: false jobs: - job: Test${{ parameters.platform }}${{ parameters.configuration }} @@ -34,6 +37,29 @@ jobs: fetchDepth: 1 fetchTags: false + - ${{ if eq(parameters.useLatestWebView2, true) }}: + - powershell: | + $edge_url = 'https://go.microsoft.com/fwlink/?linkid=2084649&Channel=Canary&language=en' + $timeout = New-TimeSpan -Minutes 6 + $timeoutSeconds = [int]$timeout.TotalSeconds + $command = { + Invoke-WebRequest -Uri $using:edge_url -OutFile $(Pipeline.Workspace)\MicrosoftEdgeSetup.exe + Write-Host "##[command]Installing Canary channel of Microsoft Edge" + Start-Process $(Pipeline.Workspace)\MicrosoftEdgeSetup.exe -ArgumentList '/silent /install' -Wait + } + + $job = Start-Job -ScriptBlock $command + Wait-Job $job -Timeout $timeoutSeconds + if ($job.State -eq "Running") { + Stop-Job $job + Write-Host "##[warning]The job was stopped because it exceeded the time limit." + } + displayName: "Install the latest MSEdge Canary" + + - script: + reg add "HKLM\Software\Policies\Microsoft\Edge\WebView2\ReleaseChannels" /v PowerToys.exe /t REG_SZ /d "3" + displayName: "Enable WebView2 Canary Channel" + - download: current displayName: Download artifacts artifact: build-${{ parameters.platform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }} diff --git a/.pipelines/v2/templates/pipeline-ci-build.yml b/.pipelines/v2/templates/pipeline-ci-build.yml index 71ebd6a33b47..8183b50c021f 100644 --- a/.pipelines/v2/templates/pipeline-ci-build.yml +++ b/.pipelines/v2/templates/pipeline-ci-build.yml @@ -22,6 +22,18 @@ parameters: - name: useVSPreview type: boolean default: false + - name: useLatestWebView2 + type: boolean + default: false + - name: useLatestWinAppSDK + type: boolean + default: false + - name: winAppSDKVersionNumber + type: string + default: 1.6 + - name: useExperimentalVersion + type: boolean + default: false stages: # Allow manual builds to skip pre-check @@ -55,6 +67,10 @@ stages: enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }} runTests: ${{ parameters.runTests }} useVSPreview: ${{ parameters.useVSPreview }} + useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }} + ${{ if eq(parameters.useLatestWinAppSDK, true) }}: + winAppSDKVersionNumber: ${{ parameters.winAppSDKVersionNumber }} + useExperimentalVersion: ${{ parameters.useExperimentalVersion }} - ${{ if eq(parameters.runTests, true) }}: - stage: Test_${{ platform }} @@ -66,3 +82,4 @@ stages: parameters: platform: ${{ platform }} configuration: Release + useLatestWebView2: ${{ parameters.useLatestWebView2 }} diff --git a/.pipelines/v2/templates/steps-ensure-dotnet-version.yml b/.pipelines/v2/templates/steps-ensure-dotnet-version.yml index c3204d065a78..b327b8004fd1 100644 --- a/.pipelines/v2/templates/steps-ensure-dotnet-version.yml +++ b/.pipelines/v2/templates/steps-ensure-dotnet-version.yml @@ -16,6 +16,10 @@ parameters: steps: - pwsh: |- curl.exe -J -L -O "https://dot.net/v1/dotnet-install.ps1" + if (-not (Test-Path dotnet-install.ps1)) { + Write-Error "Failed to download dotnet-install.ps1" + exit 1 + } $NEW_DOTNET_ROOT = "$(Agent.ToolsDirectory)\dotnet" & ./dotnet-install.ps1 -Channel "${{parameters.version}}" -InstallDir $NEW_DOTNET_ROOT Write-Host "##vso[task.setvariable variable=DOTNET_ROOT]${NEW_DOTNET_ROOT}" @@ -25,3 +29,4 @@ steps: displayName: "Install .NET ${{parameters.version}} SDK" ${{ else }}: displayName: "Install .NET ${{parameters.version}}" + retryCountOnTaskFailure: 3 diff --git a/.pipelines/v2/templates/steps-update-winappsdk-and-restore-nuget.yml b/.pipelines/v2/templates/steps-update-winappsdk-and-restore-nuget.yml new file mode 100644 index 000000000000..1fccd6de7429 --- /dev/null +++ b/.pipelines/v2/templates/steps-update-winappsdk-and-restore-nuget.yml @@ -0,0 +1,56 @@ +parameters: + - name: versionNumber + type: string + default: 1.6 + - name: useExperimentalVersion + type: boolean + default: false + +steps: +- task: NuGetAuthenticate@1 + displayName: 'NuGet Authenticate' + +- task: PowerShell@2 + displayName: Update WinAppSDK Versions + inputs: + filePath: '$(build.sourcesdirectory)\.pipelines\UpdateVersions.ps1' + arguments: > + -winAppSdkVersionNumber ${{ parameters.versionNumber }} + -useExperimentalVersion $${{ parameters.useExperimentalVersion }} + +- script: echo $(WinAppSDKVersion) + displayName: 'Display WinAppSDK Version Found' + +- task: DownloadPipelineArtifact@2 + displayName: 'Download WindowsAppSDK' + inputs: + buildType: 'specific' + project: '55e8140e-57ac-4e5f-8f9c-c7c15b51929d' + definition: '104083' + buildVersionToDownload: 'latestFromBranch' + branchName: 'refs/heads/release/${{ parameters.versionNumber }}-stable' + artifactName: 'WindowsAppSDK_Nuget_And_MSIX' + targetPath: '$(Build.SourcesDirectory)\localpackages' + +- script: dir $(Build.SourcesDirectory)\localpackages\NugetPackages + displayName: 'List downloaded packages' + +- task: NuGetCommand@2 + displayName: 'Install WindowsAppSDK' + inputs: + command: 'custom' + arguments: > + install "Microsoft.WindowsAppSDK" + -Source "$(Build.SourcesDirectory)\localpackages\NugetPackages" + -Version "$(WinAppSDKVersion)" + -OutputDirectory "$(Build.SourcesDirectory)\localpackages\output" + -FallbackSource "https://microsoft.pkgs.visualstudio.com/ProjectReunion/_packaging/Project.Reunion.nuget.internal/nuget/v3/index.json" + +- task: NuGetCommand@2 + displayName: 'Restore NuGet packages' + inputs: + command: 'restore' + feedsToUse: 'config' + nugetConfigPath: '$(build.sourcesdirectory)\nuget.config' + restoreSolution: '$(build.sourcesdirectory)\**\*.sln' + includeNuGetOrg: false \ No newline at end of file diff --git a/.pipelines/verifyDepsJsonLibraryVersions.ps1 b/.pipelines/verifyDepsJsonLibraryVersions.ps1 index 7d5fc02c1095..3837514b4667 100644 --- a/.pipelines/verifyDepsJsonLibraryVersions.ps1 +++ b/.pipelines/verifyDepsJsonLibraryVersions.ps1 @@ -15,7 +15,7 @@ Param( $referencedFileVersionsPerDll = @{} $totalFailures = 0 -Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude UITests-FancyZones*,MouseJump.Common.UnitTests* | ForEach-Object { +Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude UITests-FancyZones*,MouseJump.Common.UnitTests*,AdvancedPaste.FuzzTests* | ForEach-Object { # Temporarily exclude FancyZones UI tests because of Appium.WebDriver dependencies $depsJsonFullFileName = $_.FullName $depsJsonFileName = $_.Name diff --git a/.pipelines/verifyNoticeMdAgainstNugetPackages.ps1 b/.pipelines/verifyNoticeMdAgainstNugetPackages.ps1 index 2ee58da74556..ebef8412a7a2 100644 --- a/.pipelines/verifyNoticeMdAgainstNugetPackages.ps1 +++ b/.pipelines/verifyNoticeMdAgainstNugetPackages.ps1 @@ -46,8 +46,14 @@ $totalList = $projFiles | ForEach-Object -Parallel { foreach($p in $temp) { + # ignore "Auto-referenced" string in the output + if ($p -match "Auto-referenced") { + continue + } + # breaking item down to usable array and getting 1 and 2, see below of a sample output # > PACKAGE VERSION VERSION + # if a package is Auto-referenced, "(A)" will appear in position 1 instead of a version number. $p = -split $p $p = $p[1, 2] diff --git a/COMMUNITY.md b/COMMUNITY.md index e2e944b23bd7..8b3d7035da08 100644 --- a/COMMUNITY.md +++ b/COMMUNITY.md @@ -9,15 +9,27 @@ Names are in alphabetical order based on first name. ### [@Aaron-Junker](https://github.com/Aaron-Junker) - [Aaron Junker](https://aaron-junker.github.io) Aaron has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes. Aaron was the primary person for helping build the File Explorer preview pane handler for developer files. +### [@cgaarden](https://github.com/cgaarden) - [Christian Gaarden Gaardmark](https://www.onegreatworld.com) +Christian contributed New+ utility + ### [@CleanCodeDeveloper](https://github.com/CleanCodeDeveloper) CleanCodeDeveloper helped do massive amounts of code stability and image resizer work. +### [@plante-msft](https://github.com/plante-msft) - Connor Plante +Connor was the creator of Workspaces and helped create PowerToys Run v2 + ### [@damienleroy](https://github.com/damienleroy) - [Damien Leroy](https://www.linkedin.com/in/Damien-Leroy-b2734416a/) Damien has helped out by developing and contributing the Quick Accent utility. +### [@daverayment ](https://github.com/daverayment) - [David Rayment](https://www.linkedin.com/in/david-rayment-168b5251/) +Dave has helped improve the experience inside of Peek by adding in new features and fixing bugs. + ### [@davidegiacometti](https://github.com/davidegiacometti) - [Davide Giacometti](https://www.linkedin.com/in/davidegiacometti/) Davide has helped fix multiple bugs, added new utilities, features, as well as help us with the ARM64 effort by porting applications to .NET Core. +### [@ethanfangg](https://github.com/ethanfangg) - Ethan Fang +Ethan helped run PowerToys and worked on improving and prototyping out next generation PowerToys + ### [@franky920920](https://github.com/franky920920) - [Franky Chen](https://frankychen.net) Franky has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes to PowerToys. @@ -33,6 +45,9 @@ Jeff added in multiple new features into Keyboard manager, such as key chord sup ### [@TheJoeFin](https://github.com/TheJoeFin) - [Joe Finney](https://joefinapps.com) Joe has helped triaging, discussing, issues as well as fixing bugs and building features for Text Extractor. +### [@joadoumie](https://github.com/joadoumie) - Jordi Adoumie +Jordi helped innovate amazing new features into Advanced Paste and helped create PowerToys Run v2 + ### [@jsoref](https://github.com/jsoref) - [Josh Soref](https://check-spelling.dev/) Helping keep our spelling correct :) @@ -42,6 +57,9 @@ Color Picker is from Martin. ### [@mikeclayton](https://github.com/mikeclayton) - [Michael Clayton](https://michael-clayton.com) Michael contributed the [initial version](https://github.com/microsoft/PowerToys/issues/23216) of the Mouse Jump tool and [a number of updates](https://github.com/microsoft/PowerToys/pulls?q=is%3Apr+author%3Amikeclayton) based on his FancyMouse utility. +### [@PesBandi](https://github.com/PesBandi/) - PesBandi +PesBandi has helped do massive amounts of Quick Accent and bug fixes. + ### [@riverar](https://github.com/riverar) - [Rafael Rivera](https://withinrafael.com/) Rafael has helped do the [upgrade from CppWinRT 1.x to 2.0](https://github.com/microsoft/PowerToys/issues/1907). He directly provided feedback to the CppWinRT team for bugs from this migration as well. @@ -112,6 +130,8 @@ Find My Mouse is based on Raymond Chen's SuperSonar. Crop And Lock is based on the original work of Robert Mikhayelyan, with Program Manager support from [@kevinguo305](https://github.com/kevinguo305) - Kevin Guo. +ZoomIt's Video Recording Session code is based on Robert Mikhayelyan's https://github.com/robmikh/capturevideosample code. + ### Microsoft InVEST team This amazing team helped PowerToys develop PowerToys Run and Keyboard manager as well as update our Settings to v2. @alekhyareddy28, @arjunbalgovind, @jyuwono @laviusmotileng-ms, @ryanbodrug-microsoft, @saahmedm, @somil55, @traies, @udit3333 @@ -151,28 +171,51 @@ Other contributors: * Paul Schmitt - WWL * And many other Users! +## ZoomIt original contributors + +ZoomIt source code was originally implemented by [Sysinternals](https://sysinternals.com): + +- [@markrussinovich](https://github.com/markrussinovich) - Mark Russinovich +- [@foxmsft](https://github.com/foxmsft) - Alex Mihaiuc +- [@johnstep](https://github.com/johnstep) - John Stephens + ## PowerToys core team - [@crutkas](https://github.com/crutkas/) - Clint Rutkas - Lead -- [@ethanfangg](https://github.com/ethanfangg) - Ethan Fang - Lead -- [@cinnamon-msft](https://github.com/cinnamon-msft) - Kayla Cinnamon - Product Manager -- [@plante-msft](https://github.com/plante-msft) - Connor Plante - Product Manager +- [@cinnamon-msft](https://github.com/cinnamon-msft) - Kayla Cinnamon - Lead - [@nguyen-dows](https://github.com/nguyen-dows) - Christopher Nguyen - Product Manager -- [@joadoumie](https://github.com/joadoumie) - Jordi Adoumie - Product Manager - [@jaimecbernardo](https://github.com/jaimecbernardo) - Jaime Bernardo - Dev lead - [@dhowett](https://github.com/dhowett) - Dustin Howett - Dev lead +- [@yeelam-gordon](https://github.com/yeelam-gordon) - Gordon Lam - Dev lead +- [@jamrobot](https://github.com/jamrobot) - Jerry Xu - Dev lead - [@drawbyperpetual](https://github.com/drawbyperpetual) - Anirudha Shankar - Dev +- [@mantaionut](https://github.com/mantaionut) - Ionut Manta - Dev - [@donlaci](https://github.com/donlaci) - Laszlo Nemeth - Dev -- [@gokcekantarci](https://github.com/gokcekantarci) - Gokce Kantarci - Dev - [@SeraphimaZykova](https://github.com/SeraphimaZykova) - Seraphima Zykova - Dev - [@stefansjfw](https://github.com/stefansjfw) - Stefan Markovic - Dev +- [@lei9444](https://github.com/lei9444) - Leilei Zhang - Dev +- [@shuaiyuanxx](https://github.com/shuaiyuanxx) - Shawn Yuan - Dev +- [@moooyo](https://github.com/moooyo) - Yu Leng - Dev +- [@haoliuu](https://github.com/haoliuu) - Hao Liu - Dev +- [@chenmy77](https://github.com/chenmy77) - Mengyuan Chen - Dev +- [@chemwolf6922](https://github.com/chemwolf6922) - Feng Wang - Dev +- [@yaqingmi](https://github.com/yaqingmi) - Yaqing Mi - Dev +- [@zhaoqpcn](https://github.com/zhaoqpcn) - Qingpeng Zhao - Dev +- [@urnotdfs](https://github.com/urnotdfs) - Xiaofeng Wang - Dev +- [@zhaopy536](https://github.com/zhaopy536) - Peiyao Zhao - Dev +- [@wang563681252](https://github.com/wang563681252) - Zhaopeng Wang - Dev +- [@vanzue](https://github.com/vanzue) - Kai Tao - Dev # Former PowerToys core team members - [@indierawk2k2](https://github.com/indierawk2k2) - Mike Harsh - Product Manager +- [@ethanfangg](https://github.com/ethanfangg) - Ethan Fang - Product Manager +- [@plante-msft](https://github.com/plante-msft) - Connor Plante - Product Manager +- [@joadoumie](https://github.com/joadoumie) - Jordi Adoumie - Product Manager - [@enricogior](https://github.com/enricogior) - Enrico Giordani - Dev Lead - [@bzoz](https://github.com/bzoz) - Bartosz Sosnowski - Dev - [@ivan100sic](https://github.com/ivan100sic) - Ivan Stošić - Dev - [@mykhailopylyp](https://github.com/mykhailopylyp) - Mykhailo Pylyp - Dev - [@taras-janea](https://github.com/taras-janea) - Taras Sich - Dev - [@yuyoyuppe](https://github.com/yuyoyuppe) - Andrey Nekrasov - Dev +- [@gokcekantarci](https://github.com/gokcekantarci) - Gokce Kantarci - Dev diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 43eb58e7e0bd..02f8746a780e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,53 +1,53 @@ # PowerToys Contributor's Guide -Below is our guidance for how to report issues, propose new features, and submit contributions via Pull Requests (PRs). Our philosophy is heavily based around understanding the problem and scenarios first, this is why we follow this pattern before work has started. +Below is our guidance for reporting issues, proposing new features, and submitting contributions via Pull Requests (PRs). Our philosophy is to understand the problem and scenarios first, which is why we follow this pattern before work starts. -1. There is an issue -2. There has been a conversation -3. There is agreement on the problem, the fit for PowerToys, and the solution to the problem (implementation) +1. There is an issue. +2. There has been a conversation. +3. There is agreement on the problem, the fit for PowerToys, and the solution to the problem (implementation). -## Filing an issue +## Filing an Issue -Please follow this simple rule to help us eliminate any unnecessary wasted effort & frustration, and ensure an efficient and effective use of everyone's time - yours, ours, and other community members': +**Importance of Filing an Issue First** -> 👉 If you have a question, think you've discovered an issue, would like to propose a new feature, etc., then find/file an issue **BEFORE** starting work to fix/implement it. +Please follow this rule to help eliminate wasted effort and frustration, and to ensure an efficient and effective use of everyone’s time: -When requesting new features / enhancements, understanding problem and scenario around it is extremely important. Having additional evidence, data, tweets, blog posts, research, ... anything is extremely helpful. This information provides context to the scenario that may otherwise be lost. +> 👉 If you have a question, think you've discovered an issue, or would like to propose a new feature, please find/file an issue **BEFORE** starting work to fix/implement it. -* Don't know whether you're reporting an issue or requesting a feature? File an issue -* Have a question that you don't see answered in docs, videos, etc.? File an issue -* Want to know if we're planning on building a particular feature? File an issue -* Got a great idea for a new utility or feature? File an issue/request/idea -* Don't understand how to do something? File an issue/Community Guidance Request -* Found an existing issue that describes yours? Great - upvote and add additional commentary / info / repro-steps / etc. +When requesting new features or enhancements, providing additional evidence, data, tweets, blog posts, or research is extremely helpful. This information gives context to the scenario that may otherwise be lost. -A quick search before filing an issue also could be helpful. It is likely someone else has found the problem you're seeing, and someone may be working on or have already contributed a fix! +* Unsure whether it’s an issue or feature request? File an issue. +* Have a question that isn't answered in the docs, videos, etc.? File an issue. +* Want to know if we’re planning a particular feature? File an issue. +* Got a great idea for a new utility or feature? File an issue/request/idea. +* Don’t understand how to do something? File an issue/Community Guidance Request. +* Found an existing issue that describes yours? Great! Upvote and add additional commentary, info, or repro steps. -### How to tell the PowerToys team this is an interesting thing to focus on +A quick search before filing an issue could be helpful. It’s likely someone else has found the same problem, and they may even be working on or have already contributed a fix! -Upvote the original issue by clicking its [+😊] button and hitting 👍 (+1) icon or a different one. This way allows us to measure how impactful different issues are compared to others. The issue with comments like "+1", "me too", or similar is they actually make it harder to have a conversation and harder to quickly determine trending important requests. +### Indicating Interest in Issues ---- +To let the team know which issues are important, upvote by clicking the [+😊] button and the 👍 icon on the original issue post. Avoid comments like "+1" or "me too" as they clutter the discussion and make it harder to prioritize requests. -## Contributing fixes / features +--- -Please comment on [our "Would you like to contribute to PowerToys?" thread](https://github.com/microsoft/PowerToys/issues/28769) to let us know you're interested in working on something before you start the work. Not only does this avoid multiple people unexpectedly working on the same thing at the same time but it enables us to make sure everyone is clear on what should be done to implement any new functionality. It's less work for everyone, in the long run, to establish this up front. +## Contributing Fixes/Features -### Localization issues +Please comment on our ["Would you like to contribute to PowerToys?"](https://github.com/microsoft/PowerToys/issues/28769) thread to let us know you're interested in working on something before you start. This helps avoid multiple people unexpectedly working on the same thing and ensures everyone is clear on what should be done. It's less work for everyone to establish this up front. -Please file localization issues, so our internal localization team can identify and fix them. However we currently don't accept community Pull Requests fixing localization issues. Localization is handled by the internal Microsoft team only. +### Localization Issues -### To Spec or not to Spec +For localization issues, please file an issue to notify our internal localization team, as community PRs for localization aren't accepted. Localization is handled exclusively by the internal Microsoft team. -A key point is for everyone to understand the approach that will be taken. We want to be sure if anyone does work, we will accept it in. Items that are larger in scope we'll want some type of spec to understand what is being planned and have a discussion. Specs help collaborators discuss different approaches to solve a problem, describe how the feature will behave, how the feature will impact the user, what happens if something goes wrong, etc. Driving towards agreement in a spec, before any code is written, often results in simpler code, and less wasted effort in the long run. +### To Spec or Not to Spec -For such scenarios, once a team member has agreed with your approach, skip ahead to the section headed "Development" section below. +A key point is for everyone to understand the approach that will be taken. We want to be sure that any work done will be accepted. Larger-scope items will require a spec to outline the approach and allow for discussion. Specs help collaborators consider different solutions, describe feature behavior, and plan for errors. Achieving agreement in a spec before writing code often results in simpler code and less wasted effort. -Team members will be happy to help review specs and guide them to completion. +Once a team member has agreed with your approach, proceed to the "Development" section below. Team members are happy to help review specs and guide them to completion. ### Help Wanted -Once the team has approved an issue/spec approach to solving, development can proceed. If no developers are immediately available, the spec can be parked ready for a developer to get started. Parked specs' issues will be labeled "Help Wanted". To find a list of development opportunities waiting for developer involvement, visit the Issues and filter on [the Help-Wanted label](https://github.com/microsoft/PowerToys/labels/Help%20Wanted). +Once the team has approved an issue/spec approach, development can proceed. If no developers are immediately available, the spec may be parked and labeled "Help Wanted," ready for a developer to get started. For development opportunities, visit [Issues labeled Help Wanted](https://github.com/microsoft/PowerToys/labels/Help%20Wanted). --- @@ -55,18 +55,18 @@ Once the team has approved an issue/spec approach to solving, development can pr Follow the [development guidelines](https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md). -### Naming of features and functionality +### Naming Features and Functionality -Naming should be descriptive and straight forward. We want names to be clear about functionality and usefulness moving forward. +Names should be descriptive and straightforward, clearly reflecting functionality and usefulness. -### How can I become a collaborator on the PowerToys team +### Becoming a Collaborator on the PowerToys Team -Be a great community member. Just help out a lot and make useful additions, filing bugs/suggestions, help develop fixes and features, code reviews, and always, docs. Lets continue to make the PowerToys repository a great spot to learn and make a great set of utilities. +Be an active community member! Make helpful contributions by filing bugs, offering suggestions, developing fixes and features, conducting code reviews, and updating documentation. -When the time comes, Microsoft will reach out and help make you a formal team member. Just make sure they can reach out to you :) +When the time comes, Microsoft will reach out to you about becoming a formal team member. Just make sure they have a way to contact you. 😊 --- -## Thank you +## Thank You -Thank you in advance for your contribution! +Thank you in advance for your contribution! We appreciate your help in making PowerToys a better tool for everyone. diff --git a/DATA_AND_PRIVACY.md b/DATA_AND_PRIVACY.md index 9390d3772221..92711f00ddef 100644 --- a/DATA_AND_PRIVACY.md +++ b/DATA_AND_PRIVACY.md @@ -67,6 +67,10 @@ _If you want to find diagnostic data events in the source code, these two links Microsoft.PowerToys.TrayFlyoutModuleRunEvent Logs when a utility from the tray flyout menu is run. + + Microsoft.PowerToys.Uninstall_Success + Logs when PowerToys is successfully uninstalled (who would do such a thing!). + ### OOBE (Out-of-box experience) @@ -139,6 +143,10 @@ _If you want to find diagnostic data events in the source code, these two links Microsoft.PowerToys.AdvancedPasteInAppKeyboardShortcutEvent Triggered when a keyboard shortcut is used within the Advanced Paste interface. + + Microsoft.PowerToys.AdvancedPasteSemanticKernelFormatEvent + Triggered when Advanced Paste leverages the Semantic Kernel. + ### Always on Top @@ -933,26 +941,6 @@ _If you want to find diagnostic data events in the source code, these two links -### Video Conference Mute - - - - - - - - - - - - - - - - - -
Event NameDescription
Microsoft.PowerToys.VideoConference_CameraMutedTriggered when the camera is turned off by Video Conference Mute.
Microsoft.PowerToys.VideoConference_EnableVideoConferenceOccurs when Video Conference Mute is enabled.
Microsoft.PowerToys.VideoConference_MicrophoneMutedOccurs when the microphone is muted by Video Conference Mute.
- ### Workspaces @@ -989,6 +977,50 @@ _If you want to find diagnostic data events in the source code, these two links
+### ZoomIt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Event NameDescription
Microsoft.PowerToys.ZoomIt_EnableZoomItTriggered when ZoomIt is enabled/disabled.
Microsoft.PowerToys.ZoomIt_StartedTriggered when the ZoomIt process starts.
Microsoft.PowerToys.ZoomIt_ActivateBreakTriggered when the Break mode is entered.
Microsoft.PowerToys.ZoomIt_ActivateDrawTriggered when the Draw mode is entered.
Microsoft.PowerToys.ZoomIt_ActivateZoomTriggered when the Zoom mode is entered.
Microsoft.PowerToys.ZoomIt_ActivateLiveZoomTriggered when the Live Zoom mode is entered.
Microsoft.PowerToys.ZoomIt_ActivateDemoTypeTriggered when the DemoType mode is entered.
Microsoft.PowerToys.ZoomIt_ActivateRecordTriggered when the Record mode is entered.
Microsoft.PowerToys.ZoomIt_ActivateSnipTriggered when the Snip mode is entered.
+ - - + + + + - - - - - + + + + + + - - + + - + - + + - + - - - + + + - + - - + + - + - - - - + + + + @@ -94,4 +98,4 @@ - \ No newline at end of file + diff --git a/NOTICE.md b/NOTICE.md index e22705e2543d..84c89322827e 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -1297,7 +1297,7 @@ EXHIBIT A -Mozilla Public License. ## NuGet Packages used by PowerToys - Appium.WebDriver 4.4.5 -- Azure.AI.OpenAI 1.0.0-beta.12 +- Azure.AI.OpenAI 1.0.0-beta.17 - CommunityToolkit.Mvvm 8.2.2 - CommunityToolkit.WinUI.Animations 8.0.240109 - CommunityToolkit.WinUI.Collections 8.0.240109 @@ -1315,54 +1315,58 @@ EXHIBIT A -Mozilla Public License. - hyjiacan.pinyin4net 4.1.1 - Interop.Microsoft.Office.Interop.OneNote 1.1.0.2 - LazyCache 2.4.0 -- Mages 2.0.2 +- Mages 3.0.0 - Markdig.Signed 0.34.0 - MessagePack 2.5.187 -- Microsoft.CodeAnalysis.NetAnalyzers 9.0.0-preview.24508.2 -- Microsoft.Data.Sqlite 9.0.0 +- Microsoft.Bcl.AsyncInterfaces 9.0.1 +- Microsoft.CodeAnalysis.NetAnalyzers 9.0.0 +- Microsoft.Data.Sqlite 9.0.1 - Microsoft.Diagnostics.Tracing.TraceEvent 3.1.16 -- Microsoft.Extensions.DependencyInjection 9.0.0 -- Microsoft.Extensions.Hosting 9.0.0 -- Microsoft.Extensions.Hosting.WindowsServices 9.0.0 -- Microsoft.Extensions.Logging 9.0.0 -- Microsoft.Extensions.Logging.Abstractions 9.0.0 +- Microsoft.Extensions.DependencyInjection 9.0.1 +- Microsoft.Extensions.Hosting 9.0.1 +- Microsoft.Extensions.Hosting.WindowsServices 9.0.1 +- Microsoft.Extensions.Logging 9.0.1 +- Microsoft.Extensions.Logging.Abstractions 9.0.1 +- Microsoft.NET.ILLink.Tasks (A) +- Microsoft.SemanticKernel 1.15.0 - Microsoft.Toolkit.Uwp.Notifications 7.1.2 - Microsoft.Web.WebView2 1.0.2739.15 -- Microsoft.Win32.SystemEvents 9.0.0 -- Microsoft.Windows.Compatibility 9.0.0 +- Microsoft.Win32.SystemEvents 9.0.1 +- Microsoft.Windows.Compatibility 9.0.1 - Microsoft.Windows.CsWin32 0.2.46-beta - Microsoft.Windows.CsWinRT 2.1.5 - Microsoft.Windows.SDK.BuildTools 10.0.22621.2428 -- Microsoft.WindowsAppSDK 1.6.240923002 +- Microsoft.WindowsAppSDK 1.6.241114003 - Microsoft.Xaml.Behaviors.WinUI.Managed 2.0.9 - Microsoft.Xaml.Behaviors.Wpf 1.1.39 - ModernWpfUI 0.9.4 - Moq 4.18.4 -- MSTest 3.5.0 +- MSTest 3.6.3 - NLog.Extensions.Logging 5.3.8 - NLog.Schema 5.2.8 +- OpenAI 2.0.0 - ReverseMarkdown 4.1.0 - ScipBe.Common.Office.OneNote 3.0.1 - SharpCompress 0.37.2 - StreamJsonRpc 2.19.27 - StyleCop.Analyzers 1.2.0-beta.556 -- System.CodeDom 9.0.0 +- System.CodeDom 9.0.1 - System.CommandLine 2.0.0-beta4.22272.1 -- System.ComponentModel.Composition 9.0.0 -- System.Configuration.ConfigurationManager 9.0.0 -- System.Data.OleDb 9.0.0 +- System.ComponentModel.Composition 9.0.1 +- System.Configuration.ConfigurationManager 9.0.1 +- System.Data.OleDb 9.0.1 - System.Data.SqlClient 4.8.6 -- System.Diagnostics.EventLog 9.0.0 -- System.Diagnostics.PerformanceCounter 9.0.0 -- System.Drawing.Common 9.0.0 +- System.Diagnostics.EventLog 9.0.1 +- System.Diagnostics.PerformanceCounter 9.0.1 +- System.Drawing.Common 9.0.1 - System.IO.Abstractions 21.0.29 - System.IO.Abstractions.TestingHelpers 21.0.29 -- System.Management 9.0.0 +- System.Management 9.0.1 - System.Reactive 6.0.1 -- System.Runtime.Caching 9.0.0 -- System.ServiceProcess.ServiceController 9.0.0 -- System.Text.Encoding.CodePages 9.0.0 -- System.Text.Json 9.0.0 +- System.Runtime.Caching 9.0.1 +- System.ServiceProcess.ServiceController 9.0.1 +- System.Text.Encoding.CodePages 9.0.1 +- System.Text.Json 9.0.1 - UnicodeInformation 2.6.0 - UnitsNet 5.56.0 - UTF.Unknown 2.5.1 diff --git a/PowerToys.sln b/PowerToys.sln index 80722be402a3..870999f12c3b 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -171,6 +171,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject src\.editorconfig = src\.editorconfig .vsconfig = .vsconfig + src\Common.Dotnet.AotCompatibility.props = src\Common.Dotnet.AotCompatibility.props src\Common.Dotnet.CsWinRT.props = src\Common.Dotnet.CsWinRT.props src\Common.SelfContained.props = src\Common.SelfContained.props Cpp.Build.props = Cpp.Build.props @@ -178,7 +179,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Build.targets = Directory.Build.targets Directory.Packages.props = Directory.Packages.props src\Monaco.props = src\Monaco.props - Solution.props = Solution.props + src\Solution.props = src\Solution.props src\Version.props = src\Version.props EndProjectSection EndProject @@ -348,17 +349,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.Update", "src\Upd EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsSettings", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.csproj", "{5043CECE-E6A7-4867-9CBE-02D27D83747A}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceShared", "src\modules\videoconference\VideoConferenceShared\VideoConferenceShared.vcxproj", "{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceModule", "src\modules\videoconference\VideoConferenceModule\VideoConference.vcxproj", "{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceProxyFilter", "src\modules\videoconference\VideoConferenceProxyFilter\VideoConferenceProxyFilter.vcxproj", "{AC2857B4-103D-4D6D-9740-926EBF785042}" - ProjectSection(ProjectDependencies) = postProject - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VideoConference", "VideoConference", "{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfThumbnailProvider", "src\modules\previewpane\PdfThumbnailProvider\PdfThumbnailProvider.csproj", "{11491FD8-F921-48BF-880C-7FEA185B80A1}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-PdfThumbnailProvider", "src\modules\previewpane\UnitTests-PdfThumbnailProvider\UnitTests-PdfThumbnailProvider.csproj", "{F40C3397-1834-4530-B2D9-8F8B8456BCDF}" @@ -630,6 +620,22 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EtwTrace", "src\common\Tele EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MouseWithoutBorders.UnitTests", "src\modules\MouseWithoutBorders\MouseWithoutBorders.UnitTests\MouseWithoutBorders.UnitTests.csproj", "{66614C26-314C-4B91-9071-76133422CFEF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspacesCsharpLibrary", "src\modules\Workspaces\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj", "{89D0E199-B17A-418C-B2F8-7375B6708357}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewPlus.ShellExtension.win10", "src\modules\NewPlus\NewShellExtensionContextMenu.win10\NewPlus.ShellExtension.win10.vcxproj", "{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.UnitTests", "src\modules\AdvancedPaste\AdvancedPaste.UnitTests\AdvancedPaste.UnitTests.csproj", "{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.FuzzTests", "src\modules\AdvancedPaste\AdvancedPaste.FuzzTests\AdvancedPaste.FuzzTests.csproj", "{7F5B9557-5878-4438-A721-3E28296BA193}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ZoomIt", "ZoomIt", "{DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomIt", "src\modules\ZoomIt\ZoomIt\ZoomIt.vcxproj", "{0A84F764-3A88-44CD-AA96-41BDBD48627B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomItModuleInterface", "src\modules\ZoomIt\ZoomItModuleInterface\ZoomItModuleInterface.vcxproj", "{E4585179-2AC1-4D5F-A3FF-CFC5392F694C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomItSettingsInterop", "src\modules\ZoomIt\ZoomItSettingsInterop\ZoomItSettingsInterop.vcxproj", "{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -1500,40 +1506,6 @@ Global {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.ActiveCfg = Release|x64 {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.Build.0 = Release|x64 {5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x86.ActiveCfg = Release|x64 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|ARM64.Build.0 = Debug|ARM64 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.ActiveCfg = Debug|x64 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.Build.0 = Debug|x64 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x86.ActiveCfg = Debug|Win32 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x86.Build.0 = Debug|Win32 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|ARM64.ActiveCfg = Release|ARM64 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|ARM64.Build.0 = Release|ARM64 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.ActiveCfg = Release|x64 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.Build.0 = Release|x64 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x86.ActiveCfg = Release|Win32 - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x86.Build.0 = Release|Win32 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|ARM64.Build.0 = Debug|ARM64 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x64.ActiveCfg = Debug|x64 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x64.Build.0 = Debug|x64 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x86.ActiveCfg = Debug|x64 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|ARM64.ActiveCfg = Release|ARM64 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|ARM64.Build.0 = Release|ARM64 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x64.ActiveCfg = Release|x64 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x64.Build.0 = Release|x64 - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x86.ActiveCfg = Release|x64 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|ARM64.Build.0 = Debug|ARM64 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.ActiveCfg = Debug|x64 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.Build.0 = Debug|x64 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x86.ActiveCfg = Debug|Win32 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x86.Build.0 = Debug|Win32 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Release|ARM64.ActiveCfg = Release|ARM64 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Release|ARM64.Build.0 = Release|ARM64 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.ActiveCfg = Release|x64 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.Build.0 = Release|x64 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.ActiveCfg = Release|Win32 - {AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.Build.0 = Release|Win32 {11491FD8-F921-48BF-880C-7FEA185B80A1}.Debug|ARM64.ActiveCfg = Debug|ARM64 {11491FD8-F921-48BF-880C-7FEA185B80A1}.Debug|ARM64.Build.0 = Debug|ARM64 {11491FD8-F921-48BF-880C-7FEA185B80A1}.Debug|x64.ActiveCfg = Debug|x64 @@ -2246,6 +2218,30 @@ Global {8A08D663-4995-40E3-B42C-3F910625F284}.Release|x64.Build.0 = Release|x64 {8A08D663-4995-40E3-B42C-3F910625F284}.Release|x86.ActiveCfg = Release|x64 {8A08D663-4995-40E3-B42C-3F910625F284}.Release|x86.Build.0 = Release|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|ARM64.Build.0 = Debug|ARM64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x64.ActiveCfg = Debug|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x64.Build.0 = Debug|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x86.ActiveCfg = Debug|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x86.Build.0 = Debug|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|ARM64.ActiveCfg = Release|ARM64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|ARM64.Build.0 = Release|ARM64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x64.ActiveCfg = Release|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x64.Build.0 = Release|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x86.ActiveCfg = Release|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x86.Build.0 = Release|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|ARM64.Build.0 = Debug|ARM64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x64.ActiveCfg = Debug|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x64.Build.0 = Debug|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x86.ActiveCfg = Debug|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x86.Build.0 = Debug|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|ARM64.ActiveCfg = Release|ARM64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|ARM64.Build.0 = Release|ARM64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x64.ActiveCfg = Release|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x64.Build.0 = Release|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x86.ActiveCfg = Release|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x86.Build.0 = Release|x64 {D962A009-834F-4EEC-AABB-430DF8F98E39}.Debug|ARM64.ActiveCfg = Debug|ARM64 {D962A009-834F-4EEC-AABB-430DF8F98E39}.Debug|ARM64.Build.0 = Debug|ARM64 {D962A009-834F-4EEC-AABB-430DF8F98E39}.Debug|x64.ActiveCfg = Debug|x64 @@ -2646,30 +2642,6 @@ Global {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.Build.0 = Release|x64 {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x86.ActiveCfg = Release|x64 {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x86.Build.0 = Release|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|ARM64.Build.0 = Debug|ARM64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x64.ActiveCfg = Debug|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x64.Build.0 = Debug|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x86.ActiveCfg = Debug|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x86.Build.0 = Debug|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|ARM64.ActiveCfg = Release|ARM64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|ARM64.Build.0 = Release|ARM64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x64.ActiveCfg = Release|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x64.Build.0 = Release|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x86.ActiveCfg = Release|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x86.Build.0 = Release|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|ARM64.Build.0 = Debug|ARM64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x64.ActiveCfg = Debug|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x64.Build.0 = Debug|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x86.ActiveCfg = Debug|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x86.Build.0 = Debug|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|ARM64.ActiveCfg = Release|ARM64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|ARM64.Build.0 = Release|ARM64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x64.ActiveCfg = Release|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x64.Build.0 = Release|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x86.ActiveCfg = Release|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x86.Build.0 = Release|x64 {B31FCC55-B5A4-4EA7-B414-2DCEAE6AF332}.Debug|ARM64.ActiveCfg = Debug|ARM64 {B31FCC55-B5A4-4EA7-B414-2DCEAE6AF332}.Debug|ARM64.Build.0 = Debug|ARM64 {B31FCC55-B5A4-4EA7-B414-2DCEAE6AF332}.Debug|x64.ActiveCfg = Debug|x64 @@ -2778,6 +2750,90 @@ Global {66614C26-314C-4B91-9071-76133422CFEF}.Release|x64.Build.0 = Release|x64 {66614C26-314C-4B91-9071-76133422CFEF}.Release|x86.ActiveCfg = Release|x64 {66614C26-314C-4B91-9071-76133422CFEF}.Release|x86.Build.0 = Release|x64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|ARM64.Build.0 = Debug|ARM64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|x64.ActiveCfg = Debug|x64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|x64.Build.0 = Debug|x64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|x86.ActiveCfg = Debug|x64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Debug|x86.Build.0 = Debug|x64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Release|ARM64.ActiveCfg = Release|ARM64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Release|ARM64.Build.0 = Release|ARM64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Release|x64.ActiveCfg = Release|x64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Release|x64.Build.0 = Release|x64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Release|x86.ActiveCfg = Release|x64 + {89D0E199-B17A-418C-B2F8-7375B6708357}.Release|x86.Build.0 = Release|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|ARM64.Build.0 = Debug|ARM64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|x64.ActiveCfg = Debug|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|x64.Build.0 = Debug|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|x86.ActiveCfg = Debug|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|x86.Build.0 = Debug|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|ARM64.ActiveCfg = Release|ARM64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|ARM64.Build.0 = Release|ARM64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x64.ActiveCfg = Release|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x64.Build.0 = Release|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x86.ActiveCfg = Release|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x86.Build.0 = Release|x64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|ARM64.Build.0 = Debug|ARM64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|x64.ActiveCfg = Debug|x64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|x64.Build.0 = Debug|x64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|x86.ActiveCfg = Debug|x64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|x86.Build.0 = Debug|x64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|ARM64.ActiveCfg = Release|ARM64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|ARM64.Build.0 = Release|ARM64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|x64.ActiveCfg = Release|x64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|x64.Build.0 = Release|x64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|x86.ActiveCfg = Release|x64 + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|x86.Build.0 = Release|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|ARM64.Build.0 = Debug|ARM64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x64.ActiveCfg = Debug|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x64.Build.0 = Debug|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x86.ActiveCfg = Debug|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x86.Build.0 = Debug|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|ARM64.ActiveCfg = Release|ARM64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|ARM64.Build.0 = Release|ARM64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|x64.ActiveCfg = Release|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|x64.Build.0 = Release|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|x86.ActiveCfg = Release|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|x86.Build.0 = Release|x64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Debug|ARM64.Build.0 = Debug|ARM64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Debug|x64.ActiveCfg = Debug|x64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Debug|x64.Build.0 = Debug|x64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Debug|x86.ActiveCfg = Debug|x64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Debug|x86.Build.0 = Debug|x64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Release|ARM64.ActiveCfg = Release|ARM64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Release|ARM64.Build.0 = Release|ARM64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Release|x64.ActiveCfg = Release|x64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Release|x64.Build.0 = Release|x64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Release|x86.ActiveCfg = Release|x64 + {0A84F764-3A88-44CD-AA96-41BDBD48627B}.Release|x86.Build.0 = Release|x64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Debug|ARM64.Build.0 = Debug|ARM64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Debug|x64.ActiveCfg = Debug|x64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Debug|x64.Build.0 = Debug|x64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Debug|x86.ActiveCfg = Debug|x64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Debug|x86.Build.0 = Debug|x64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Release|ARM64.ActiveCfg = Release|ARM64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Release|ARM64.Build.0 = Release|ARM64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Release|x64.ActiveCfg = Release|x64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Release|x64.Build.0 = Release|x64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Release|x86.ActiveCfg = Release|x64 + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C}.Release|x86.Build.0 = Release|x64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Debug|ARM64.Build.0 = Debug|ARM64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Debug|x64.ActiveCfg = Debug|x64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Debug|x64.Build.0 = Debug|x64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Debug|x86.ActiveCfg = Debug|x64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Debug|x86.Build.0 = Debug|x64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|ARM64.ActiveCfg = Release|ARM64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|ARM64.Build.0 = Release|ARM64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x64.ActiveCfg = Release|x64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x64.Build.0 = Release|x64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x86.ActiveCfg = Release|x64 + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x86.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2881,10 +2937,6 @@ Global {48804216-2A0E-4168-A6D8-9CD068D14227} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} {FF1D7936-842A-4BBB-8BEA-E9FE796DE700} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} {5043CECE-E6A7-4867-9CBE-02D27D83747A} = {4AFC9975-2456-4C70-94A4-84073C1CED93} - {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} - {5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} - {AC2857B4-103D-4D6D-9740-926EBF785042} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} - {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {11491FD8-F921-48BF-880C-7FEA185B80A1} = {2F305555-C296-497E-AC20-5FA1B237996A} {F40C3397-1834-4530-B2D9-8F8B8456BCDF} = {2F305555-C296-497E-AC20-5FA1B237996A} {A2D583F0-B70C-4462-B1F0-8E81AFB7BA85} = {4AFC9975-2456-4C70-94A4-84073C1CED93} @@ -2956,6 +3008,8 @@ Global {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC} {A663E672-B26D-4EC0-BEAB-FE2E424AC46F} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC} {8A08D663-4995-40E3-B42C-3F910625F284} = {322566EF-20DC-43A6-B9F8-616AF942579A} + {923DF87C-CA99-4D1C-B1D2-959174E95BFA} = {322566EF-20DC-43A6-B9F8-616AF942579A} + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77} = {322566EF-20DC-43A6-B9F8-616AF942579A} {D962A009-834F-4EEC-AABB-430DF8F98E39} = {322566EF-20DC-43A6-B9F8-616AF942579A} {9873BA05-4C41-4819-9283-CF45D795431B} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {FC373B24-3293-453C-AAF5-CF2909DCEE6A} = {9873BA05-4C41-4819-9283-CF45D795431B} @@ -2995,8 +3049,6 @@ Global {8ACB33D9-C95B-47D4-8363-9731EE0930A0} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC} {CA716AE6-FE5C-40AC-BB8F-2C87912687AC} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {F055103B-F80B-4D0C-BF48-057C55620033} = {5A7818A8-109C-4E1C-850D-1A654E234B0E} - {923DF87C-CA99-4D1C-B1D2-959174E95BFA} = {322566EF-20DC-43A6-B9F8-616AF942579A} - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77} = {322566EF-20DC-43A6-B9F8-616AF942579A} {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {BE126CBB-AE12-406A-9837-A05ACFCA57A7} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} {14CB58B7-D280-4A7A-95DE-4B2DF14EA000} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} @@ -3009,6 +3061,14 @@ Global {37D07516-4185-43A4-924F-3C7A5D95ECF6} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} {8F021B46-362B-485C-BFBA-CCF83E820CBD} = {8F62026A-294B-41C6-8839-87463613F216} {66614C26-314C-4B91-9071-76133422CFEF} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC} + {89D0E199-B17A-418C-B2F8-7375B6708357} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC} + {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE} = {9873BA05-4C41-4819-9283-CF45D795431B} + {7F5B9557-5878-4438-A721-3E28296BA193} = {9873BA05-4C41-4819-9283-CF45D795431B} + {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} + {0A84F764-3A88-44CD-AA96-41BDBD48627B} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C} + {E4585179-2AC1-4D5F-A3FF-CFC5392F694C} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C} + {CA7D8106-30B9-4AEC-9D05-B69B31B8C461} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0} diff --git a/README.md b/README.md index 2fd9e6e755f9..11646244adef 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline | [New+](https://aka.ms/PowerToysOverview_NewPlus) | [Peek](https://aka.ms/PowerToysOverview_Peek) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) | | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | | [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | -| [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) | +| [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Workspaces](https://aka.ms/PowerToysOverview_Workspaces) | [ZoomIt](https://aka.ms/PowerToysOverview_PowerToysOverview_ZoomIt) | ## Installing and running Microsoft PowerToys @@ -34,19 +34,19 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline Go to the [Microsoft PowerToys GitHub releases page][github-release-link] and click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user. -[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.87%22 -[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.86%22 -[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.86.0/PowerToysUserSetup-0.86.0-x64.exe -[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.86.0/PowerToysUserSetup-0.86.0-arm64.exe -[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.86.0/PowerToysSetup-0.86.0-x64.exe -[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.86.0/PowerToysSetup-0.86.0-arm64.exe - +[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.88%22 +[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.87%22 +[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.87.1/PowerToysUserSetup-0.87.1-x64.exe +[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.87.1/PowerToysUserSetup-0.87.1-arm64.exe +[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.87.1/PowerToysSetup-0.87.1-x64.exe +[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.87.1/PowerToysSetup-0.87.1-arm64.exe + | Description | Filename | sha256 hash | |----------------|----------|-------------| -| Per user - x64 | [PowerToysUserSetup-0.86.0-x64.exe][ptUserX64] | CFB9608B28B8FF12C9A7C9814A6EF981636EB5AB261DC278C28EC93FD959CCE2 | -| Per user - ARM64 | [PowerToysUserSetup-0.86.0-arm64.exe][ptUserArm64] | 861CEDBFDCDA993D1D1056E3280319D5EA45D142CA3C737AB1FB4FABD651A5F5 | -| Machine wide - x64 | [PowerToysSetup-0.86.0-x64.exe][ptMachineX64] | 857DE9DC5938D9602F82DFD6183DB5E6823B875A412AEC59B4BE93617E27E9CD | -| Machine wide - ARM64 | [PowerToysSetup-0.86.0-arm64.exe][ptMachineArm64] | 6F37192534C195A02A80AAE1E449DF61C894C50763096A06195581801943FA31 | +| Per user - x64 | [PowerToysUserSetup-0.87.1-x64.exe][ptUserX64] | 8EFAF47ED00BF230D2C2CC3CB6765C903A6A47E0AAED0BBB329CEF918207B486 | +| Per user - ARM64 | [PowerToysUserSetup-0.87.1-arm64.exe][ptUserArm64] | 212FC8055789BD2DC4DE554B9AEE291A9C077907E263A302939266263A9D512B | +| Machine wide - x64 | [PowerToysSetup-0.87.1-x64.exe][ptMachineX64] | 69AD65DDAC6436AEF292D2CC6AB1530021CE98083CB3F5FD3380A52A3B0DBB9A | +| Machine wide - ARM64 | [PowerToysSetup-0.87.1-arm64.exe][ptMachineArm64] | AEC9F1D02F1E23F0C1FCFDF95C337C962902394F44C0568012DF78BEDB45CF19 | This is our preferred method. @@ -92,103 +92,115 @@ For guidance on developing for PowerToys, please read the [developer docs](/doc/ Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on. -### 0.86 - October 2024 Update +### 0.87 - December 2024 Update In this release, we focused on new features, stability, and improvements. **Highlights** - - - Advanced Paste has new abilities: Image to text, and paste to file (text / png / html). - - In settings, we've adjusted the left navigation to group the utilities. As the number of utilities shipped with PowerToys keeps growing, we felt this was a needed adjustment. Thanks everyone for your feedback! - - Workspaces received many bug fixes, including the proper launching of many instances of the same application in the same workspace. Note, we are still actively looking at how to properly handle PWA detection. - - We've added a diagnostic data (telemetry) opt-in option in the Settings General tab. As it is off-by-default, we encourage users to turn it on as that helps direct our development efforts and their journeys. More information about the data we collect can be found in the [PowerToys Data and Privacy documentation](https://aka.ms/powertoys-data-and-privacy-documentation) and what each event does. -### General - - - Added a setting for diagnostic data (telemetry) opt-in (off by default, however, see above for why we encourage you to opt-in!) and user controls to view data. - - Improved exception logging by adding the type of Exception and InnerException. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! + - Advanced Paste has a new feature called "Advanced AI" that uses Semantic Kernel to allow setting up the orchestration of sequential clipboard transformations. + - Workspaces supports Progressive Web Applications. + - Workspaces has a new feature to move existing windows instead of creating new ones. + - Mouse Jump added new settings to allow customization of screens pop-up. Thanks [@mikeclayton](https://github.com/mikeclayton)! + - New+ now works on Windows 10. Thanks [@cgaarden](https://github.com/cgaarden)! + - Quick Accent allows selecting the character sets that should appear on the UI. Thanks [@Sirozha1337](https://github.com/Sirozha1337)! ### Advanced Paste - - Added new built-in actions: Image to text, and paste txt, png or html as a file. + - Added a new optional feature allowing using AI to set up the orchestration of sequential clipboard transformations. -### Mouse Jump +### Awake + + - Initialization, logging and tray icon setup improvements. Thanks [@dend](https://github.com/dend)! - - Refactored the common classes into a separate project. Thanks [@mikeclayton](https://github.com/mikeclayton)! - - Brought back the telemetry events that were deleted across previous refactoring efforts. +### File Explorer add-ons -### Mouse Without Borders + - Preview Pane extensions now use the PerMonitorV2 DPI mode to fix errors on different scales. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! + +### Keyboard Manager. + + - Added labels to the IME On, IME Off keys. Thanks [@kit494way](https://github.com/kit494way)! + - Fixed an issue that caused the Shift key to remain stuck if a numpad key was mapped to the Shift key. + +### Monaco Preview + + - Added support for .ahk files to be shown as a plaintext file in Peek and File Explorer add-ons. Thanks [@daverayment](https://github.com/daverayment)! + - Added support for .ion files to be shown as a plaintext file in Peek and File Explorer add-ons. Thanks [@octastylos-pseudodipteros](https://github.com/octastylos-pseudodipteros)! + - Added support for syntax highlighting for .srt files in Peek and File Explorer add-ons. Thanks [@PesBandi](https://github.com/PesBandi)! + +### Mouse Jump - - Refactored the Logger common classes. Thanks [@mikeclayton](https://github.com/mikeclayton)! + - Allow customizing the appearance of the UI of the Mouse Jump pop-up. Thanks [@mikeclayton](https://github.com/mikeclayton)! ### New+ - - Fixed the telemetry event for when the modules is enabled or disabled. (This was a hotfix for 0.85) - - Fixed bug when creating folders or files that contain Unicode characters. Thanks [@cgaarden](https://github.com/cgaarden)! - - Fixed bug when the name of a new folder collided with an already existing folder. Thanks [@cgaarden](https://github.com/cgaarden)! - - Updated the New+ icons to the fluent style. + - Added support for Windows 10. Thanks [@cgaarden](https://github.com/cgaarden)! + - Fixed an issue causing the renaming of new files to not trigger some times. Thanks [@cgaarden](https://github.com/cgaarden)! + - Updated the New+ icons. Thanks [@niels9001](https://github.com/niels9001)! ### Peek - - Folder preview enumeration of size and number of files is now more responsive and faster. Thanks [@daverayment](https://github.com/daverayment)! + - Peek now checks local capabilities to decide what image formats Image Previewer is able to support. Thanks [@daverayment](https://github.com/daverayment)! + - Fixed an issue causing the Code Files Previewer to not load correctly under certain conditions. Thanks [@daverayment](https://github.com/daverayment)! + - Refactored, improved and fixed logging when loading the user settings file. Thanks [@daverayment](https://github.com/daverayment)! ### PowerToys Run - - Handled a culture not found error when checking for right-to-left languages. - - Fixed the WebSearch plugin results title being trimmed in the UI. Thanks [@octastylos-pseudodipteros](https://github.com/octastylos-pseudodipteros)! - - The Unit Converter plugin will now show more significant digits. Thanks [@PesBandi](https://github.com/PesBandi)! - - Improved error handling when copying to the clipboard results in an error. Thanks [@PesBandi](https://github.com/PesBandi)! + - Added a scoring function for proper ordering of the WindowWalker plugin results. Thanks [@andbartol](https://github.com/andbartol)! + - Added UUIDv7 support to the ValueGenerator plugin. Thanks [@frederik-hoeft](https://github.com/frederik-hoeft)! + - The calculator plugin now allows scientific notation numbers with a lowercase 'e'. Thanks [@PesBandi](https://github.com/PesBandi)! + - Ported the UI from WPF-UI to .NET 9 WPF, to fix "Desktop composition is disabled" crashes. ### Quick Accent - - Added support for the Serbian Cyrillic character set. Thanks [@Sirozha1337](https://github.com/Sirozha1337)! + - Added a setting to allow selecting which character sets to show. Thanks [@Sirozha1337](https://github.com/Sirozha1337)! -### Registry Preview +### Screen Ruler - - Adopted the Monaco Editor as the UI text editor. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! + - Added a Setting to also allow showing measurements in inches, centimeters or millimeters. Thanks [@Sophanatprime](https://github.com/Sophanatprime)! ### Settings - - Fixed a crash when trying to access a non-existing templates folder from the New+ page. (This was a hotfix for 0.85) - - Added a navigation tree to group utilities in the left navigation menu. - - Sorted the list of languages in the language selection combo box in the General tab. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! - - Fixed the state of the info bar about templates not being backed up to not close and react to the module's enabled state in the New+ page. Thanks [@htcfreek](https://github.com/htcfreek)! - - Fixed a crash caused by a dangling thread. - - Clicking a notification about there being an update available should now correctly open the Settings application in the General tab. - - Fixed a UI freeze when trying to access the Diagnostic Data Viewer files. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! + - Fixed an issue causing all the links to milestones in the "What's new?" OOBE page to point to the same milestone. + - Removed extra space from the Welcome page. Thanks [@agarwalishita](https://github.com/agarwalishita)! + - Updated left navigation bar icons. Thanks [@niels9001](https://github.com/niels9001)! + - Fixed accessibility issues in the dashboard page. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! ### Workspaces - - Fixed launching the incorrect workspace when launching many workspaces quickly through shortcuts. (This was a hotfix for 0.85) - - Fixed launching many instances of the same application in a workspace. - - Fixed a crash when a previously captured monitor ID no longer existed. - - Fixed an issue causing the wrong coordinates to be saved for minimized applications. - - Fixed an issue causing a crash when stress testing workspace launching. - - Fixed application launching when UAC is off and every application always runs elevated. + - Added support for Progressive Web Applications to Workspaces. + - Implemented a feature to move existing windows instead of creating new ones. + - Fixed a crash when opening the workspaces editor that was caused by passing incorrect encoder parameters when saving Bitmap files. + - Workspaces editor position is now saved so that we can start it at the same position when we open it again. + - Fixed an issue causing many instances of the same application to be put in the same position instead of the intended position due to timer issues. + - Fixed detection of exact application version when many versions of the same application are installed. ### Documentation - - Added HackMD plugin mention to thirdPartyRunPlugins.md. Thanks [@8LWXpg](https://github.com/8LWXpg)! - - Added SSH plugin mention to thirdPartyRunPlugins.md. Thanks [@8LWXpg](https://github.com/8LWXpg)! - - Added the [Data and Privacy documentation](https://github.com/microsoft/PowerToys/blob/main/DATA_AND_PRIVACY.md) to the repo. + - Improved language in CONTRIBUTE.md. Thanks [@sanskaarz](https://github.com/sanskaarz)! + - Added Bilibili plugin mention to thirdPartyRunPlugins.md. Thanks [@Whuihuan](https://github.com/Whuihuan)! + - Added CanIUse and TailwindCSS plugins mention to thirdPartyRunPlugins.md. Thanks [@skttl](https://github.com/skttl)! + - Added HttpStatusCodes plugin mention to thirdPartyRunPlugins.md. Thanks [@grzhan](https://github.com/grzhan)! + - Updated COMMUNITY.md with more contributors. ### Development - - Fixed the CI precheck action to take into account the recent changes in CI actions. - - Added the new Microsoft org issue types to the issue templates. Thanks [@Aaron-Junker](https://github.com/Aaron-Junker)! - - Updated System.Text.Json to 8.0.5 and System.Runtime.Caching to 8.0.1 and related dependencies to the latest to address security reports. Thanks [@snickler](https://github.com/snickler)! - - Updated WinAppSDK to 1.6.1 and CsWinRT to 2.1.5. Thanks [@snickler](https://github.com/snickler)! - - Upgraded the WpfUI dependency to 3.0.5. - - Updated MessagePack to 2.5.187 and StreamJsonRpc to 2.19.27 to address security reports. - - Removed some of the hacks that are no longer needed that tried to force same dependency versions in .csproj files. - - Removed the Markdown file exclusions from the conditions that trigger a full CI test. - - CI fails again when there are XAML style errors in a PR. - - Fixed CI actions that were not failing when one of the powershell scripts they tried to run was failing. - - Fixed analyzer violations to allow fully building PowerToys on Visual Studio 17.12. Thanks [@snickler](https://github.com/snickler)! + - Upgraded to .NET 9. Thanks [@snickler](https://github.com/snickler)! + - Fixed building on Visual Studio 17.12. + - Upgraded the System.IO.Abstractions dependency to 21.0.29. Thanks [@davidegiacometti](https://github.com/davidegiacometti)! + - Upgraded the WindowsAppSDK dependency to 1.6.241114003. Thanks [@shuaiyuanxx](https://github.com/shuaiyuanxx)! + - Upgraded the MSTest dependency to 3.6.3. Thanks [@Youssef1313](https://github.com/Youssef1313)! + - Upgraded the check-spelling CI dependency to 0.0.24 and fixed related spell checking issues. Thanks [@jsoref](https://github.com/jsoref)! + - Removed duplicate names from the spellcheck allowed names file. Thanks [@htcfreek](https://github.com/htcfreek)! + - Improved logging of asynchronous methods call stacks when logging an error. + - Created a MSBuild props file to be imported by other projects to enable AOT support. + - Made the Peek utility source code AOT compatible. + - Updated .editorconfig rules to relax squiggly IDE errors in Visual Studio 17.12. Thanks [@snickler](https://github.com/snickler)! + - Moved Xaml.Styler from the root to the src folder. -#### What is being planned for version 0.87 +#### What is being planned for version 0.88 -For [v0.87][github-next-release-work], we'll work on the items below: +For [v0.88][github-next-release-work], we'll work on the items below: - Stability / bug fixes - New module: File Actions Menu @@ -214,6 +226,5 @@ The application logs basic diagnostic data (telemetry). For more information on [winget-link]: https://github.com/microsoft/winget-cli#installing-the-client [roadmap]: https://github.com/microsoft/PowerToys/wiki/Roadmap [privacy-link]: http://go.microsoft.com/fwlink/?LinkId=521839 -[vidConfOverview]: https://aka.ms/PowerToysOverview_VideoConference [loc-bug]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=translation_issue.md&title= [usingPowerToys-docs-link]: https://aka.ms/powertoys-docs diff --git a/doc/devdocs/akaLinks.md b/doc/devdocs/akaLinks.md index 6b0dcac1d895..eae60c1161e2 100644 --- a/doc/devdocs/akaLinks.md +++ b/doc/devdocs/akaLinks.md @@ -29,7 +29,6 @@ | PowerToysOverview_PowerRename | https://learn.microsoft.com/windows/powertoys/powerrename | | PowerToysOverview_PowerToysRun | https://learn.microsoft.com/windows/powertoys/run | | PowerToysOverview_ShortcutGuide | https://learn.microsoft.com/windows/powertoys/shortcut-guide | -| PowerToysOverview_VideoConference | https://learn.microsoft.com/windows/powertoys/video-conference-mute | | powerToysPowerLauncherImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerLauncher_small.png | | powerToysPowerLauncherSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerLauncher_large.png | | powerToysPowerPreviewImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerPreview_small.png | @@ -42,6 +41,4 @@ | powerToysRequestFeature | https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=feature_request.md&title= | | powerToysShortcutGuideImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ShortcutGuide_small.png | | powerToysShortcutGuideSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ShortcutGuide_large.png | -| powerToysVideoConferenceImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/VideoConference_small.png | -| powerToysVideoConferenceSettingImage | https://github.com/microsoft/PowerToys/wiki/images/overview/VideoConference_large.png | | powertoyswiki | https://github.com/microsoft/PowerToys/wiki | diff --git a/doc/devdocs/common/FilePreviewCommon.md b/doc/devdocs/common/FilePreviewCommon.md index 85b74ca7e73d..33c11aad285d 100644 --- a/doc/devdocs/common/FilePreviewCommon.md +++ b/doc/devdocs/common/FilePreviewCommon.md @@ -47,7 +47,7 @@ registerAdditionalNewLanguage("id", [".fileExtension"], idDefinition(), monaco) * The id can be anything. Recommended is one of the file extensions. For example "php" or "reg". -4. In case you wish to add a custom color for a token, you can do so by adding the following line to [`customTokenColors.js`](/src/Monaco/customTokenColors.js): +4. In case you wish to add a custom color for a token, you can do so by adding the following line to [`customTokenThemeRules.js`](/src/Monaco/customTokenThemeRules.js): ```javascript {token: 'token-name', foreground: 'ff0000'} ``` diff --git a/doc/devdocs/common/common.md b/doc/devdocs/common/common.md index 5d5d906a4423..9bc6e39e16bd 100644 --- a/doc/devdocs/common/common.md +++ b/doc/devdocs/common/common.md @@ -97,6 +97,6 @@ namespace ``` -Note: since _background activation_ implies that your toast handler will be invoked in a separate process, you can't share data directly from within a handler and your PT process. Also, since PT is currently a Desktop Bridge app, _foreground activation_ is [handled the same as background](https://learn.microsoft.com/windows/uwp/design/shell/tiles-and-notifications/send-local-toast-desktop-cpp-wrl#foreground-vs-background-activation), therefore we don't make a dedicated API for it. You can read more on the rationale of the current design [here](https://github.com/microsoft/PowerToys/pull/1178#issue-368768337). +Note: since _background activation_ implies that your toast handler will be invoked in a separate process, you can't share data directly from within a handler and your PT process. Also, since PT is currently a Desktop Bridge app, _foreground activation_ is [handled the same as background](https://learn.microsoft.com/windows/uwp/design/shell/tiles-and-notifications/send-local-toast-desktop-cpp-wrl#foreground-vs-background-activation), therefore we don't make a dedicated API for it. You can read more on the [rationale of the current design](https://github.com/microsoft/PowerToys/pull/1178#issue-368768337). diff --git a/doc/devdocs/localization.md b/doc/devdocs/localization.md index a3842a9f8c0b..322f90ab6d92 100644 --- a/doc/devdocs/localization.md +++ b/doc/devdocs/localization.md @@ -17,13 +17,13 @@ ## Localization on the pipeline (CDPX) [The localization step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L45-L52) is run on the pipeline before the solution is built. This step runs the [build-localization](https://github.com/microsoft/PowerToys/blob/main/.pipelines/build-localization.cmd) script, which generates resx files for all the projects with localization enabled using the `Localization.XLoc` package. -The [`Localization.XLoc`](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L24-L25) tool is run on the repo root, and it checks for all occurrences of `LocProject.json`. Each localized project has a `LocProject.json` file in the project root, which contains the location of the English resx file, list of languages for localization, and the output path where the localized resx files are to be copied to. In addition to this, some other parameters can be set, such as whether the language ID should be added as a folder in the file path or in the file name. When the CDPX pipeline is run, the localization team is notified of changes in the English resx files. For each project with localization enabled, a `loc` folder (see [this](https://github.com/microsoft/PowerToys/tree/main/src/modules/launcher/Microsoft.Launcher/loc) for example) is created in the same directory as the `LocProject.json` file. The folder contains language specific folders which in turn have a nested folder path equivalent to `OutputPath` in the `LocProject.json`. Each of these folders contain one `lcl` file. The `lcl` files contain the English resources along with their translation for that language. These are described in more detail [here](#lcl-files). Once the `.resx` files are generated, they will be used during the `Build PowerToys` step for localized versions of the modules. +The [`Localization.XLoc`](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L24-L25) tool is run on the repo root, and it checks for all occurrences of `LocProject.json`. Each localized project has a `LocProject.json` file in the project root, which contains the location of the English resx file, list of languages for localization, and the output path where the localized resx files are to be copied to. In addition to this, some other parameters can be set, such as whether the language ID should be added as a folder in the file path or in the file name. When the CDPX pipeline is run, the localization team is notified of changes in the English resx files. For each project with localization enabled, a `loc` folder (see [this](https://github.com/microsoft/PowerToys/tree/main/src/modules/launcher/Microsoft.Launcher/loc) for example) is created in the same directory as the `LocProject.json` file. The folder contains language specific folders which in turn have a nested folder path equivalent to `OutputPath` in the `LocProject.json`. Each of these folders contain one `lcl` file. The `lcl` files contain the English resources along with their translation for that language. These are described in more detail in the [Lcl files section](#lcl-files). Once the `.resx` files are generated, they will be used during the `Build PowerToys` step for localized versions of the modules. -Since the localization script requires certain nuget packages, the [`restore-localization`](https://github.com/microsoft/PowerToys/blob/main/.pipelines/restore-localization.cmd) script is run before running `build-localization` to install all the required packages. This script must [run in the `restore` step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L37-L39) of pipeline because [the host is network isolated](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipelinhttps://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipeline?anchor=overview) at the `build` step. The [Toolset package source](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L23) is used for this. +Since the localization script requires certain nuget packages, the [`restore-localization`](https://github.com/microsoft/PowerToys/blob/main/.pipelines/restore-localization.cmd) script is run before running `build-localization` to install all the required packages. This script must [run in the `restore` step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L37-L39) of pipeline because [the host is network isolated](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipeline?anchor=overview) at the `build` step. The [Toolset package source](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L23) is used for this. -The process and variables that can be tweaked on the pipeline are described in more detail [here](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/290/Localization). +The process and variables that can be tweaked on the pipeline are described in more detail on [onebranch (account required) under Localization](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/290/Localization). -The localized resource dlls for C# projects are added to the MSI only for build on the pipeline. This is done by checking if the [`IsPipeline` variable is defined](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/installer/PowerToysSetup/Product.wxs#L804-L805), which gets defined before building the installer on the pipeline [here](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/.pipelines/build-installer.cmd#L4). This is done because the localized resx files are only present on the pipeline, and not having this check would result in the installer project failing to build locally. +The localized resource dlls for C# projects are added to the MSI only for build on the pipeline. This is done by checking if the [`IsPipeline` variable is defined](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/installer/PowerToysSetup/Product.wxs#L804-L805), which gets defined before [building the installer on the pipeline](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/.pipelines/build-installer.cmd#L4). This is done because the localized resx files are only present on the pipeline, and not having this check would result in the installer project failing to build locally. ## Enabling localization on a new project To enable localization on a new project, the first step is to create a file `LocProject.json` in the project root. @@ -45,7 +45,7 @@ For example, for a project in the folder `src\path` where the resx file is prese ] } ``` -The rest of the steps depend on the project type and are covered in the sections below. The steps to add the localized files to the MSI can be found [here](#Enabling-localized-MSI-for-a-new-project). +The rest of the steps depend on the project type and are covered in the sections below. The steps to add the localized files to the MSI can be found in [Enabling localized MSI for a new project](#Enabling-localized-MSI-for-a-new-project). ### C++ C++ projects do not support `resx` files, and instead use `rc` files along with `resource.h` files. The CDPX pipeline however doesn't support localizing `rc` files and the other alternative they support is directly translating the resources from the binary which makes it harder to maintain resources. To avoid this, a custom script has been added which expects a resx file and converts the entries to an rc file with a string table and adds resource declarations to a resource.h file so that the resources can be compiled with the C++ project. @@ -59,7 +59,7 @@ After generating the resx file, rename the existing rc and h files to ProjName.b ``` -This event runs a script which generates a resource.h and ProjName.rc in the `Generated Files` folder using the strings in all the resx files along with the existing information in resource.base.h and ProjName.base.rc. The script can be found [here](https://github.com/microsoft/PowerToys/blob/main/tools/build/convert-resx-to-rc.ps1). The script uses [`resgen`](https://learn.microsoft.com/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert) to convert the resx file to a string table expected in the .rc file format. When the resources are added to the rc file the `IDS_` prefix is added and resource names are in upper case (as it was originally). Any occurrences of `"` in the string resource is escaped as `""` to prevent build errors. The string tables are added to the rc file in the following format: +This event runs a script which generates a resource.h and ProjName.rc in the `Generated Files` folder using the strings in all the resx files along with the existing information in resource.base.h and ProjName.base.rc. The script is [convert-resx-to-rc.ps1](https://github.com/microsoft/PowerToys/blob/main/tools/build/convert-resx-to-rc.ps1). The script uses [`resgen`](https://learn.microsoft.com/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert) to convert the resx file to a string table expected in the .rc file format. When the resources are added to the rc file the `IDS_` prefix is added and resource names are in upper case (as it was originally). Any occurrences of `"` in the string resource is escaped as `""` to prevent build errors. The string tables are added to the rc file in the following format: ``` #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US @@ -71,7 +71,7 @@ END #endif ``` -Since there is no API to identify the `AFX_TARG_*`, `LANG_*` or `SUBLANG_*` values from each langId from the pipeline, these are hardcoded in the script (for each language) as done [here](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/tools/build/convert-resx-to-rc.ps1#L50-L77). **If any other languages are added in the future, this script will have to be updated.** In order to determine what are the language codes, you can open the rc file in Resource View, right click the string table and press `Insert Copy` and choose the corresponding language. This autogenerates the required code and can be used to figure out the language codes. The files also add the resource declarations to a resource.h file, starting from 101 by default(this can be changed by an optional argument). Since the output files will be generated in `Generated Files`, any includes in these two files will require an additional `..\` and wherever resource.h is used, it will have to be included as `Generated Files\resource.h`. While adding `resource.base.h` and `ProjName.base.rc` to the vcxproj, these should be modified to not participate in the build to avoid build errors: +Since there is no API to identify the `AFX_TARG_*`, `LANG_*` or `SUBLANG_*` values from each langId from the pipeline, these are hardcoded in the script (for each language) as done in [lines 50-77 of `convert-resx-to-rc.ps1`](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/tools/build/convert-resx-to-rc.ps1#L50-L77). **If any other languages are added in the future, this script will have to be updated.** In order to determine what are the language codes, you can open the rc file in Resource View, right click the string table and press `Insert Copy` and choose the corresponding language. This autogenerates the required code and can be used to figure out the language codes. The files also add the resource declarations to a resource.h file, starting from 101 by default(this can be changed by an optional argument). Since the output files will be generated in `Generated Files`, any includes in these two files will require an additional `..\` and wherever resource.h is used, it will have to be included as `Generated Files\resource.h`. While adding `resource.base.h` and `ProjName.base.rc` to the vcxproj, these should be modified to not participate in the build to avoid build errors: ``` ``` @@ -86,7 +86,7 @@ Since C# projects natively support `resx` files, the only step required here is ``` -**Note:** Building with localized resources may cause a build warning `Referenced assembly 'mscorlib.dll' targets a different processor` which is a VS bug. More details can be found [here](https://github.com/microsoft/PowerToys/issues/7269). +**Note:** Building with localized resources may cause a build warning `Referenced assembly 'mscorlib.dll' targets a different processor` which is a VS bug. More details can be found in [PowerToys issue #7269](https://github.com/microsoft/PowerToys/issues/7269). **Note:** If a project needs to be migrated from XAML resources to resx, the easiest way to convert the resources would be to change to format to `=` separates resources by either manually (by Ctrl+H on a text editor), or by a script, and then running [`resgen`](https://learn.microsoft.com/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert) on `Developer Command Prompt for VS` to convert it to resx format. ``` @@ -153,7 +153,7 @@ For C++ and UWP projects no additional files are generated with localization tha ``` For C# projects, satellite dlls are generated when the project is built. For a project named `ProjName`, files are created in the format `langId\ProjName.resources.dll` where `langId` is in the same format as the lcl files. The satellite dlls need to be included with the MSI, but they must be added only if the solution is built from the build farm, as the localized resx files will not be present on local machines (and that could cause local builds of the installer to fail). -This can be done by adding the directory name of the project [here](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/installer/PowerToysSetup/Product.wxs#L806) and a resource component for the project can be created [here](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/installer/PowerToysSetup/Product.wxs#L845-L847) in this format: +This can be done by adding the directory name of the project to [Product.wxs near line 806](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/installer/PowerToysSetup/Product.wxs#L806) and a resource component for the project can be created in [Product.wxs near lines 845-847](https://github.com/microsoft/PowerToys/blob/f92bd6ffd38014c228544bb8d68d0937ce4c2b6d/installer/PowerToysSetup/Product.wxs#L845-L847) in this format: ``` diff --git a/doc/devdocs/modules/keyboardmanager/keyboardeventhandlers.md b/doc/devdocs/modules/keyboardmanager/keyboardeventhandlers.md index cb3d1561ce8f..a2ee09777116 100644 --- a/doc/devdocs/modules/keyboardmanager/keyboardeventhandlers.md +++ b/doc/devdocs/modules/keyboardmanager/keyboardeventhandlers.md @@ -25,13 +25,13 @@ This file contains documentation for all the methods involved in key/shortcut re - Check if any shortcut remap is currently invoked. This is required to ensure that two remaps don't occur simultaneously at a time, and we send key up events for the shortcuts only if they are actually invoked and not for artificial key up events. In addition to that, while a remap is in the middle of execution, the keyboard state will not match the physical keys, so we do not want a remap Ctrl+A to Ctrl+V to also trigger the remap from Ctrl+V to Alt+V on pressing Ctrl+A on the keyboard. - Get the remap table as per the `activatedApp` argument (i.e. if it is empty, we get the global shortcut remap table and otherwise we get the corresponding app-specific shortcut remap table). - Iterate over the list of remaps in descending order of number of keys in the shortcut. This is required **for shortcut to key remaps** to ensure that if a user has both Ctrl+A and Ctrl+Shift+A remapped to some keys, and the user presses Ctrl+Shift+A, then we prefer the Ctrl+Shift+A remap. This logic would not be required if there were only shortcut to shortcut remaps, as they are invoked only on exact match. -- If any shortcut was found to be invoked (from the first step), then we skip till we find the matching shortcut remap. If not we check if the modifiers of the original shortcut are pressed down. If they are, we check if the current key event is a key down event and it matches the action key of the original shortcut. For shortcut to shortcut and for disabling a shortcut [we have an additional step](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L208-L212) where we check if any other key is pressed apart from the original shortcut. This is required because for these two features we allow the remaps only if those exact keys are pressed. The method used for this is described in detail [here](keyboardmanagercommon.md#IsKeyboardStateClearExceptShortcut). If a win key was pressed, we store whether it was the left or the right one, in order to determine which key to set for remaps from/to the common Win key code which we added. This is so that pressing and releasing Left Win key results in that Win key getting modified and not the Right Win key. +- If any shortcut was found to be invoked (from the first step), then we skip till we find the matching shortcut remap. If not we check if the modifiers of the original shortcut are pressed down. If they are, we check if the current key event is a key down event and it matches the action key of the original shortcut. For shortcut to shortcut and for disabling a shortcut [we have an additional step](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L208-L212) where we check if any other key is pressed apart from the original shortcut. This is required because for these two features we allow the remaps only if those exact keys are pressed. The method used for this is [described in detail](keyboardmanagercommon.md#IsKeyboardStateClearExceptShortcut). If a win key was pressed, we store whether it was the left or the right one, in order to determine which key to set for remaps from/to the common Win key code which we added. This is so that pressing and releasing Left Win key results in that Win key getting modified and not the Right Win key. - If the remap is to a key, we send a dummy key event followed by releasing the original shortcut's modifiers and setting the target key (or doing nothing if it is remapped to disable) and we suppress the event. - If the remap is to a shortcut, if the modifiers in the original shortcut are present in the target, we only set the additional modifiers and the action key of the target. If it isn't, we send a dummy key event followed by releasing the modifiers which are not common, and setting the remaining ones in the target along with the action key. - For both cases, we set the `isShortcutInvoked` flag to true, and set the `KeyboardManagerState.activatedApp` if it is an app-specific shortcut remap. - For the `isShortcutInvoked` is true scenario (i.e. the initial remap keydown section is done) there are several cases depending on the key pressed or released: - [**Case 1:**](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L339-L430) If a modifier in the original shortcut is released, we need to reset back to the physical keys pressed. - - For remap to shortcut, we release the target action key if it is currently pressed, and depending on whether all the modifiers of the original shortcut are present in the target, we release the target modifiers that are not common, and set the remaining original shortcut modifiers except the one that was released. We do not need to send the original action key as that will get generate it's own key event if it is held down. + - For remap to shortcut, we release the target action key if it is currently pressed, and depending on whether all the modifiers of the original shortcut are present in the target, we release the target modifiers that are not common, and set the remaining original shortcut modifiers except the one that was released. We do not need to send the original action key as that will get generate its own key event if it is held down. - For remap to key, we release the target key if it is pressed (and it is not remapped to Disable), and we set the original shortcut modifiers. - For both the cases we send a dummy key event at the end, since we are setting modifiers without any other key after that, and we reset all the remap variables. - [**Case 2:**](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L435-L461) If the original shortcut's action key is pressed again, we send the target shortcut's action key or the target key again (or for disable we just suppress the event). @@ -57,9 +57,9 @@ This file contains documentation for all the methods involved in key/shortcut re ## HandleAppSpecificShortcutRemapEvent [This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L754-L809) is used for handling app-specific shortcut to shortcut and shortcut to key remaps. The general logic is as follows: - Check if the `dwExtraInfo` field is set to `KEYBOARDMANAGER_SHORTCUT_FLAG`. This indicates that the key event was generated by the KBM shortcut remap method using `SendInput`. This ensures that we don't read events generated by the shortcut remap method, but we still read events which are generated by the key remap method. -- Get the name of the process in the foreground. This is done using `GetCurrentApplication` which uses `GetForegroundWindow` to get the window handle and `get_process_path` from the common lib. This approach can fail for UWP apps in full screen, so for that scenario we use the `GetGUIThreadInfo` approach to find the correct window handle, and hence the correct process name. This method is described in more detail [here](keyboardmanagercommon.md#Foreground-app-detection) +- Get the name of the process in the foreground. This is done using `GetCurrentApplication` which uses `GetForegroundWindow` to get the window handle and `get_process_path` from the common lib. This approach can fail for UWP apps in full screen, so for that scenario we use the `GetGUIThreadInfo` approach to find the correct window handle, and hence the correct process name. This method is [described in more detail](keyboardmanagercommon.md#Foreground-app-detection) - By checking `KeyboardManagerState.GetActivatedApp` we check if an app-specific shortcut is currently invoked. If so, we consider this application to be the activated app. This is required because some shortcut remaps could cause the current app to lose focus and hence until the shortcut is completely released we should allow that remap to continue, otherwise the user could end up in a state where some keys do not get released. For example: remap Ctrl+A to Alt+Tab for Edge, when a user presses Ctrl+A the window loses focus as Alt+Tab gets executed. -- If there is no app-specific shortcut currently invoked, we check if the foreground process is present in the list of app-specific remaps, either with or without the file extension and case insensitive. If it is, this is considered to be the activated app. +- If there is no app-specific shortcut currently invoked, we check if the foreground process is present in the list of app-specific remaps, either with or without the file extension and case-insensitive. If it is, this is considered to be the activated app. - Call `HandleShortcutRemapEvent` with the `activatedApp` argument so that app-specific shortcut remapping takes place if it applies for the current key event. ## HandleSingleKeyToggleToModEvent (Obsolete - Code from PoC which is commented out) @@ -81,4 +81,4 @@ The [`MockedInput`](https://github.com/microsoft/PowerToys/blob/main/src/modules - For modifiers the behavior is slightly different as if the key state of the L/R version is modified, it should also modify the common version, and if a common version is released, it should release both the L and R versions. ### Tests for single key remaps and shortcut remaps -Using the MockedInput handler, all the expected (and known) key scenarios that can occur for while pressing a [remapped key](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/SingleKeyRemappingTests.cpp) or [remapped shortcut](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/OSLevelShortcutRemappingTests.cpp) are tested. The foreground app behavior which is specific to app-specific shortcuts is tested [here](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/AppSpecificShortcutRemappingTests.cpp). +Using the MockedInput handler, all the expected (and known) key scenarios that can occur for while pressing a [remapped key](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/SingleKeyRemappingTests.cpp) or [remapped shortcut](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/OSLevelShortcutRemappingTests.cpp) are tested. The foreground app behavior which is specific to app-specific shortcuts is tested in [AppSpecificShortcutRemappingTests.cpp](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/AppSpecificShortcutRemappingTests.cpp). diff --git a/doc/devdocs/modules/keyboardmanager/keyboardmanager.md b/doc/devdocs/modules/keyboardmanager/keyboardmanager.md index b58a51b74fd1..c570a735e88b 100644 --- a/doc/devdocs/modules/keyboardmanager/keyboardmanager.md +++ b/doc/devdocs/modules/keyboardmanager/keyboardmanager.md @@ -27,14 +27,14 @@ This file contains the documentation for the KeyboardManager PowerToy module whi The `KeyboardManager` module has [3 main class members](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L54-L61): - A static pointer to the current object of `KeyboardManager`. This is required for using the `KeyboardManager` object in the low level keyboard hook handler as that method must be static. This is described in more detail in [this section](#Low-level-keyboard-hook-handler). - An object of type `Input`, which is used for all the operations that involving getting or setting keyboard states. This is wrapped in an object to allow testing the remapping methods. -- An object of type `KeyboardManagerState`. This object contains all the data related to remappings and is also used in the sense of a View Model as it used to communicate common data that is shared between the KBM UI and the backend. This class is described in more detail [here](keyboardmanagercommon.md#keyboardmanagerstate). +- An object of type `KeyboardManagerState`. This object contains all the data related to remappings and is also used in the sense of a [View Model as it used to communicate common data that is shared between the KBM UI and the backend](keyboardmanagercommon.md#keyboardmanagerstate). ## Enable/Disable -On enabling KBM, the low level keyboard hook is started, and it is unhooked on disable. This is done to allow users to manually restart KBM if some other application which registers a keyboard hook was launched after PowerToys, so that it can be brought back to the highest priority hook (as the last hook to be registered receives the input first as mentioned [here](https://learn.microsoft.com/windows/win32/winmsg/about-hooks#hook-procedures)). +On enabling KBM, the low level keyboard hook is started, and it is unhooked on disable. This is done to allow users to manually restart KBM if some other application which registers a keyboard hook was launched after PowerToys, so that it can be brought back to the highest priority hook (as the [last hook to be registered receives the input first](https://learn.microsoft.com/windows/win32/winmsg/about-hooks#hook-procedures)). In addition to stopping the hook, any active KBM UI windows are also closed on disabling. This is done because the KBM UI uses the same keyboard hook for the Type button where you can type a key/shortcut, so if KBM is disabled the windows would not be completely functional. -The enable/disable code can be found [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L301-L322) +The [enable/disable code can be found in dllmain.cpp](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L301-L322) ## Settings format KBM uses two sets of settings files. @@ -101,10 +101,10 @@ KBM uses two sets of settings files. - `originalKeys` stores the key/shortcut which is to be pressed for the remap, and `newKeys` stores the key/shortcut which is to be executed. - Both contain semi-colon separated virtual key codes. For `remapKeys`, `originalKeys` must have only one key code, whereas for `remapShortcuts` it must have at least two key codes. - `inProcess` sub-key was added in `remapKeys` because there was a possibility of adding the registry based remapping approach (used by [SharpKeys](https://github.com/randyrants/sharpkeys)), so that would be under a separate sub-key while `inProcess` would be for keyboard hook based remaps. This was deprioritized as there weren't enough requests for it. - - `remapShortcuts` is split into `global` and `appSpecific`, where `global` remaps would apply to all applications, whereas `appSpecific` would apply on when the `targetApp` is in focus. `targetApp` must be the process name of the app (with or without it's extension), e.g. `msedge` or `msedge.exe` for Microsoft Edge. + - `remapShortcuts` is split into `global` and `appSpecific`, where `global` remaps would apply to all applications, whereas `appSpecific` would apply on when the `targetApp` is in focus. `targetApp` must be the process name of the app (with or without its extension), e.g. `msedge` or `msedge.exe` for Microsoft Edge. ## Loading settings -KBM settings are loaded only on the C++ side only at start up, in the [constructor](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L67-L68). The settings file may get modified from the KBM UI on applying new remappings, but the file is not read again. The files are read from the PowerToys Settings process whenever a change is made to the file (using a FileWatcher) or whenever the KBM page is opened. The settings are updated only when the user presses the OK button from either of the Remap Keys or Remap Shortcuts windows. This is described in more detail [here](keyboardmanagerui.md#ok-and-cancel-button). +KBM settings are loaded only on the C++ side only at start up, in the [constructor](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L67-L68). The settings file may get modified from the KBM UI on applying new remappings, but the file is not read again. The files are read from the PowerToys Settings process whenever a change is made to the file (using a FileWatcher) or whenever the KBM page is opened. The settings are updated only when the user presses the OK button from either of the Remap Keys or Remap Shortcuts windows. This is described in more detail [keyboardmanagerui: OK and Cancel button](keyboardmanagerui.md#ok-and-cancel-button). ## Low level keyboard hook handler Since the [`hook_proc`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L330-L349) cannot be a member function in the class, this is declared `static` and a `static pointer` to the `KeyboardManager` project is used ([`keyboardmanager_object_ptr`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L54-L55)). @@ -117,22 +117,23 @@ As seen in the code for `hook_proc`, similar to other keyboard hooks in PowerToy The [`HandleKeyboardHookEvent`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L384-L458) is the method which calls the corresponding remapping methods in the required order. The following checks are executed in order: - **`KeyboardManagerState.AreRemappingsEnabled`:** This returns false while the KBM remap tables are getting updated. If it is in this state, `HandleKeyboardHookEvent` returns `0`, i.e. the key event is not suppressed and is forwarded normally. - **Check for `KEYBOARDMANAGER_SUPPRESS_FLAG`:** If the key event has the suppress flag, the method returns 1 to suppress the key event. -- **[`KeyboardManagerState.DetectSingleRemapKeyUIBackend`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L399-L408):** This method is used for handling hook operations for the single key Type UI in the Remap keys window. If the Remap keys window is open, then `HandleKeyboardHookEvent` returns `0` and the key event is forwarded normally. If the left column Type button is clicked on the Remap keys window and the window is in focus, then the key event is suppressed and the UI is updated with the latest key from the recent key events. This method is described in more detail [here](keyboardmanagercommon.md#DetectSingleRemapKeyUIBackend-and-DetectShortcutUIBackend). -- **[`KeyboardManagerState.DetectShortcutUIBackend(data, true)`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L410-L419):** This method is used for handling hook operations for the shortcut Type UI in the Remap keys window (when `isRemapKey` arg is `true`). If the Remap keys window is open, then `HandleKeyboardHookEvent` returns `0` and the key event is forwarded normally. If the right column Type button is clicked on the Remap keys window and the window is in focus, then the key event is suppressed and the UI is updated with the shortcut from the recent key events. This method is described in more detail [here](keyboardmanagercommon.md#DetectSingleRemapKeyUIBackend-and-DetectShortcutUIBackend). -- **`HandleSingleKeyRemapEvent`:** This method handles the single key remap logic. If a remapping takes place, the key event is suppressed. This method is described in more detail [here](keyboardeventhandlers.md#HandleSingleKeyRemapEvent). +- **[`KeyboardManagerState.DetectSingleRemapKeyUIBackend`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L399-L408):** This method is used for handling hook operations for the single key Type UI in the Remap keys window. If the Remap keys window is open, then `HandleKeyboardHookEvent` returns `0` and the key event is forwarded normally. If the left column Type button is clicked on the Remap keys window and the window is in focus, then the key event is suppressed and the UI is updated with the latest key from the recent key events. This method is described in more detail in [DetectSingleRemapKeyUIBackend and DetectShortcutUIBackend](keyboardmanagercommon.md#DetectSingleRemapKeyUIBackend-and-DetectShortcutUIBackend). +- **[`KeyboardManagerState.DetectShortcutUIBackend(data, true)`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L410-L419):** This method is used for handling hook operations for the shortcut Type UI in the Remap keys window (when `isRemapKey` arg is `true`). If the Remap keys window is open, then `HandleKeyboardHookEvent` returns `0` and the key event is forwarded normally. If the right column Type button is clicked on the Remap keys window and the window is in focus, then the key event is suppressed and the UI is updated with the shortcut from the recent key events. This method is also described in more detail in [DetectSingleRemapKeyUIBackend and DetectShortcutUIBackend](keyboardmanagercommon.md#DetectSingleRemapKeyUIBackend-and-DetectShortcutUIBackend). +- **`HandleSingleKeyRemapEvent`:** This method handles the single key remap logic. If a remapping takes place, the key event is suppressed. This method is described in more detail in [HandleSingleKeyRemapEvent](keyboardeventhandlers.md#HandleSingleKeyRemapEvent). - **[`KeyboardManagerState.DetectShortcutUIBackend(data, false)`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L430-L439):** This method is used for handling hook operations for the shortcut Type UI in the Remap shortcuts window (when `isRemapKey` arg is `false`). If the Remap shortcuts window is open, then `HandleKeyboardHookEvent` returns `0` and the key event is forwarded normally. If the Type button is clicked on the Remap shortcuts window and the window is in focus, then the key event is suppressed and the UI is updated with the shortcut from the recent key events. **Since this is executed after the single key remap method, all single key remappings are applied when the user is on the Remap shortcuts window.** -- **`HandleAppSpecificShortcutRemapEvent`:** This method handles the app-specific shortcut remap logic. If a remapping takes place, the key event is suppressed. This method is described in more detail [here](keyboardeventhandlers.md#HandleAppSpecificShortcutRemapEvent). **Since this is executed after the single key remap method, single key remappings have precedence over shortcut remaps and are correspondingly reflected in shortcut remaps.** -- **`HandleOSLevelShortcutRemapEvent`:** This method handles the global shortcut remap logic. If a remapping takes place, the key event is suppressed. This method is described in more detail [here](keyboardeventhandlers.md#HandleOSLevelShortcutRemapEvent). The app-specific remap method is executed before this because if a shortcut is remapped to different keys/shortcuts for a particular app and globally, the app-specific variant should be preferred if that app is in focus. **Since this is executed after the single key remap method, single key remappings have precedence over shortcut remaps and are correspondingly reflected in shortcut remaps.** +- **`HandleAppSpecificShortcutRemapEvent`:** This method handles the app-specific shortcut remap logic. If a remapping takes place, the key event is suppressed. This method is described in more detail in [HandleAppSpecificShortcutRemapEvent](keyboardeventhandlers.md#HandleAppSpecificShortcutRemapEvent). **Since this is executed after the single key remap method, single key remappings have precedence over shortcut remaps and are correspondingly reflected in shortcut remaps.** +- **`HandleOSLevelShortcutRemapEvent`:** This method handles the global shortcut remap logic. If a remapping takes place, the key event is suppressed. This method is described in more detail under [HandleOSLevelShortcutRemapEvent](keyboardeventhandlers.md#HandleOSLevelShortcutRemapEvent). The app-specific remap method is executed before this because if a shortcut is remapped to different keys/shortcuts for a particular app and globally, the app-specific variant should be preferred if that app is in focus. **Since this is executed after the single key remap method, single key remappings have precedence over shortcut remaps and are correspondingly reflected in shortcut remaps.** **Note:** Single key remaps need to be executed before shortcut remaps, because otherwise there can be several logical issues. For example if a user has Ctrl remapped to X and Ctrl+A remapped to Y, we can't detect Ctrl+A because the moment Ctrl is pressed it would be remapped to X before the system ever sees Ctrl+A. This is why the design decision was made to separate Remap keys and Remap shortcuts, and all key remaps are reflected in the shortcut remaps. ## Custom Action to launch KBM UI -KBM uses the [`call_custom_action`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L249-L280) method from the `PowertoyModuleIface` in order to launch the KBM UI when the user clicks the Remap a key or Remap a shortcut button from the KBM settings page. On clicking the button, we check if there is already any active KBM UI window, and if there is it is brought to the foreground. If not, the corresponding KBM UI window is launched on a separate detached thread. The UI is described in more detail [here](keyboardmanagerui.md). +KBM uses the [`call_custom_action`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L249-L280) method from the `PowertoyModuleIface` in order to launch the KBM UI when the user clicks the Remap a key or Remap a shortcut button from the KBM settings page. On clicking the button, we check if there is already any active KBM UI window, and if there is it is brought to the foreground. If not, the corresponding KBM UI window is launched on a separate detached thread. The UI is described in more detail in [Keyboard Manager UI](keyboardmanagerui.md). ## SendInput Special Scenarios ### Extended keys -Certain keys such as the arrow keys, right Ctrl/Alt, and Del/Home/Ins, etc need to be sent with the `KEYEVENTF_EXTENDEDKEY` flag because otherwise the NumPad versions get sent, which can cause weird behavior when NumLock is on. The code can be found [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L190-L194) and the list of extended keys in code can be found [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L73-L98). Docs about extended keys can be found [here](https://learn.microsoft.com/windows/win32/inputdev/about-keyboard-input#extended-key-flag). +Certain keys such as the arrow keys, right Ctrl/Alt, and Del/Home/Ins, etc need to be sent with the `KEYEVENTF_EXTENDEDKEY` flag because otherwise the NumPad versions get sent, which can cause weird behavior when NumLock is on. The code can be found where [`SetKeyEvent` checks `IsExtendedKey(keyCode)`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L190-L194) and the list of extended keys in code can be found in [`IsExtendedKey`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L73-L98). Docs about extended keys can be found in [Keyboard Input Overview: Extended-Key Flag +](https://learn.microsoft.com/windows/win32/inputdev/about-keyboard-input#extended-key-flag). The weird behavior that is caused by this can be found at these issues: - https://github.com/microsoft/PowerToys/issues/3478 @@ -140,7 +141,7 @@ The weird behavior that is caused by this can be found at these issues: - https://github.com/microsoft/PowerToys/issues/3981 ### Scan code -Certain applications (such as Windows Terminal) may filter out key events which are set to scan code 0. Even though the `KEYEVENTF_SCANCODE` flag is not set, the `wScan` field is still sent, which defaults to 0. To avoid this issue we use the `MapVirtualKey` API to find the scan code from the virtual key code. Code can be found [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L196-L198). +Certain applications (such as Windows Terminal) may filter out key events which are set to scan code 0. Even though the `KEYEVENTF_SCANCODE` flag is not set, the `wScan` field is still sent, which defaults to 0. To avoid this issue we use the `MapVirtualKey` API to find the scan code from the virtual key code. Code can be found in [`SetKeyEvent`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L196-L198). ## Special Scenarios Since we are using low level keyboard hooks and not actual OS level input handling certain scenarios with input require workarounds as do they not interact well with the OS input logic directly. These are covered in the sub-sections below. @@ -156,7 +157,7 @@ The dummy key event is currently used in the following places (the linked code s - https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L509-L510 ### Suppressing Num Lock in a keyboard hook -The Num Lock key state is updated by the OS before it is intercepted by low level hooks. This causes the issue that even if you suppress a Num Lock key event, Num Lock will still get toggled. In order to work around this, in the [`hook_proc`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L340-L344) whenever we suppress a Num Lock key down event, we send an additional Num Lock key up followed by key down so that the Num Lock state is reverted to it's previous value before the suppressed event. These are sent with a `KEYBOARDMANAGER_SUPPRESS_FLAG` in the `dwExtraInfo` field, so that we suppress them at the start of the hook (see code [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L811-L825)). Since these events will update the Num Lock state before the low level hooks, by suppressing them we ensure that these are not sent to any other hooks/applications and hence are only processed by the OS. +The Num Lock key state is updated by the OS before it is intercepted by low level hooks. This causes the issue that even if you suppress a Num Lock key event, Num Lock will still get toggled. In order to work around this, in the [`hook_proc`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L340-L344) whenever we suppress a Num Lock key down event, we send an additional Num Lock key up followed by key down so that the Num Lock state is reverted to its previous value before the suppressed event. These are sent with a `KEYBOARDMANAGER_SUPPRESS_FLAG` in the `dwExtraInfo` field, so that we suppress them at the start of the hook (see code in [`SetNumLockToPreviousState`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L811-L825)). Since these events will update the Num Lock state before the low level hooks, by suppressing them we ensure that these are not sent to any other hooks/applications and hence are only processed by the OS. This assumes that KBM is the last hook to be registered (since another hook-based app like AutoHotkey could remap NumLock to some other key which could mess up this logic). @@ -167,7 +168,7 @@ While using Japanese IME on Windows, shortcuts like Shift/Alt/Ctrl + These shortcuts are detected before low level hooks, and hence cause issues while remapping Caps Lock to Shift/Alt/Ctrl or vice-versa, as there could be an intermediate state where the system detects both the keys as being pressed. This results in a state where the modifier key does not get released since the OS suppresses the key up messages before they reach the low level hooks. -In order to work around this when a key down for the modifier is being processed, we send a key up for the modifier key with the `KEYBOARDMANAGER_SUPPRESS_FLAG` in the `dwExtraInfo` field, so that we suppress them at the start of the hook, and this key event would only be processed by the OS, without getting forwarded to other hooks/apps. The approach is described in more detail at [this comment](https://github.com/microsoft/PowerToys/issues/3397#issuecomment-640136416), as discussed with the AutoHotkey team. The code for the workaround can be found [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L827-L846). Tests for these scenarios have also been added at: +In order to work around this when a key down for the modifier is being processed, we send a key up for the modifier key with the `KEYBOARDMANAGER_SUPPRESS_FLAG` in the `dwExtraInfo` field, so that we suppress them at the start of the hook, and this key event would only be processed by the OS, without getting forwarded to other hooks/apps. The approach is described in more detail at [this comment](https://github.com/microsoft/PowerToys/issues/3397#issuecomment-640136416), as discussed with the AutoHotkey team. The code for the workaround can be found in [`ResetIfModifierKeyForLowerLevelKeyHandlers`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L827-L846). Tests for these scenarios have also been added at: - [Tests for workaround on single key remaps](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/test/SingleKeyRemappingTests.cpp#L110-L219) - [Tests for workaround on shortcut remaps](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/test/OSLevelShortcutRemappingTests.cpp#L1935-L2144) @@ -189,8 +190,8 @@ Using a driver approach has the benefit of not depending on precedence orders as ## Telemetry Keyboard Manager emits the following telemetry events (implemented in [trace.h](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/trace.h) and [trace.cpp](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/trace.cpp)): -- **`KeyboardManager_EnableKeyboardManager`:** Logs a `boolean` value storing the KBM toggle state. It is logged whenever KBM is enabled or disabled (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L305-L316)). -- **`KeyboardManager_KeyRemapCount`:** Logs the number of key to key and key to shortcut remaps (i.e. all the remaps on the Remap a key window). This gets logged on saving new settings in the Remap a key window (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L159-L163)). -- **`KeyboardManager_OSLevelShortcutRemapCount`:** Logs the number of global shortcut to shortcut and shortcut to key remaps. This gets logged on saving new settings in the Remap a shortcut window (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L220)). -- **`KeyboardManager_AppSpecificShortcutRemapCount`:** Logs the number of app-specific shortcut to shortcut and shortcut to key remaps. This gets logged on saving new settings in the Remap a shortcut window (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L221)). -- **`KeyboardManager_Error`:** Logs the occurrence of an error in KBM with the name of the method, error code and the corresponding error message. This is currently used only for logging `SetWindowsHookEx` failures (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L364-L369)). +- **`KeyboardManager_EnableKeyboardManager`:** Logs a `boolean` value storing the KBM toggle state. It is logged whenever KBM is enabled or disabled (emitted in [`enable`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L305-L306) and [`disable`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L315-L316)). +- **`KeyboardManager_KeyRemapCount`:** Logs the number of key to key and key to shortcut remaps (i.e. all the remaps on the Remap a key window). This gets logged on saving new settings in the Remap a key window (emitted at [the end of `ApplySingleKeyRemappings`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L159-L163)). +- **`KeyboardManager_OSLevelShortcutRemapCount`:** Logs the number of global shortcut to shortcut and shortcut to key remaps. This gets logged on saving new settings in the Remap a shortcut window (emitted at [the end of `ApplyShortcutRemappings`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L220)). +- **`KeyboardManager_AppSpecificShortcutRemapCount`:** Logs the number of app-specific shortcut to shortcut and shortcut to key remaps. This gets logged on saving new settings in the Remap a shortcut window (emitted [after calling `OSLevelShortcutRemapCount` in `ApplyShortcutRemappings`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L221)). +- **`KeyboardManager_Error`:** Logs the occurrence of an error in KBM with the name of the method, error code and the corresponding error message. This is currently used only for logging `SetWindowsHookEx` failures (emitted [at the end of `start_lowlevel_keyboard_hook`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L364-L369)). diff --git a/doc/devdocs/modules/keyboardmanager/keyboardmanagercommon.md b/doc/devdocs/modules/keyboardmanager/keyboardmanagercommon.md index e0258db13dd6..3132d3f29de0 100644 --- a/doc/devdocs/modules/keyboardmanager/keyboardmanagercommon.md +++ b/doc/devdocs/modules/keyboardmanager/keyboardmanagercommon.md @@ -37,7 +37,7 @@ The [`SaveConfigToFile`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a To prevent the UI thread and low level hook thread from concurrently accessing the remap tables we use an [`atomic bool` variable](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyboardManagerState.h#L91-L92), which is set to `true` while the tables are getting updated. When this is `true` the hook will skip all remappings. Use of mutexes in the hook were removed to prevent reentrant mutex bugs. ## KeyDelay -[This class](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/KeyDelay.cpp) implements a queue based approach for processing key events and based on the time difference between key down and key up events [executes separate methods for `ShortPress`, `LongPress` or `LongPressReleased`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.h#L69-L72). The class is used for the hold Enter/Esc functionality required for making the Type window accessible and prevent keyboard traps (see [this](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp#L273-L292) for an example of it's usage). The `KeyEvents` are added to the queue from the hook thread of KBM, and a separate [`DelayThread`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.cpp#L142-L166) is used to process the key events by checking the `time` member in the key event. The thresholds for short vs long press and hold wait timeouts are `static` constants, but if the module is extended for other purposes these could be made into arguments. +The [KeyDelay class](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyDelay.cpp) implements a queue based approach for processing key events and based on the time difference between key down and key up events [executes separate methods for `ShortPress`, `LongPress` or `LongPressReleased`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.h#L69-L72). The class is used for the hold Enter/Esc functionality required for making the Type window accessible and prevent keyboard traps (see [this call to `keyboardManagerState.RegisterKeyDelay`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp#L273-L292) for an example of its usage). The `KeyEvents` are added to the queue from the hook thread of KBM, and a separate [`DelayThread`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.cpp#L142-L166) is used to process the key events by checking the `time` member in the key event. The thresholds for short vs long press and hold wait timeouts are `static` constants, but if the module is extended for other purposes these could be made into arguments. **Note:** [Deletion of the `KeyDelay`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.cpp#L4-L12) object should never be called from the `DelayThread` i.e. from within one of the 3 handlers, as it can re-enter the mutex and would lead to a deadlock. This can be avoided by either deleting it on a separate thread or as done in the KBM UI, on the dispatcher thread. See [this PR](https://github.com/microsoft/PowerToys/pull/6959#issue-496583547) for more details on this issue. @@ -45,16 +45,16 @@ To prevent the UI thread and low level hook thread from concurrently accessing t The [`Shortcut` class](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/Shortcut.h) is a data structure for storing key combinations which are valid shortcuts and it contains several methods which are used for shortcut specific operations. [`RemapShortcut`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/RemapShortcut.h) consists of a shortcut/key union (`std::variant`), along with other boolean flags which are required on the hook side for storing any relevant keyboard states mid-execution. ### IsKeyboardStateClearExceptShortcut -[This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L665-L813) is used by the `HandleShortcutRemapEvent` to check if any other keys on the keyboard have been pressed apart from the keys in the shortcut. This is required because shortcut to shortcut remaps should not be applied if the shortcut is pressed with other keys. The method iterates over all the possible key codes, except any keys that are considered reserved, unassigned, OEM-specific or undefined, as well as mouse buttons (see list [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L628-L663)). +[This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L665-L813) is used by the `HandleShortcutRemapEvent` to check if any other keys on the keyboard have been pressed apart from the keys in the shortcut. This is required because shortcut to shortcut remaps should not be applied if the shortcut is pressed with other keys. The method iterates over all the possible key codes, except any keys that are considered reserved, unassigned, OEM-specific or undefined, as well as mouse buttons (see [list in `IgnoreKeyCode`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L628-L663)). ### CheckModifiersKeyboardState [This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L517-L614) uses `GetVirtualKeyState` (internally calls `GetAsyncKeyState` in production code), to check if all the modifiers of the current shortcut are being pressed. Since Win doesn't have a non-L/R key code we check this by checking both LWIN and RWIN. ### Tests -Tests for some methods in the `Shortcut` class can be found [here](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/ShortcutTests.cpp). +Tests for some methods in the `Shortcut` class can be found in [`OSLevelShortcutRemappingTests.cpp`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/KeyboardManagerEngineTest/OSLevelShortcutRemappingTests.cpp) and [`AppSpecificShortcutRemappingTests.cpp`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/KeyboardManagerEngineTest/AppSpecificShortcutRemappingTests.cpp). ## Helpers -[This namespace](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/Helpers.cpp) has any methods which are used across either UI or the backend which aren't specific to either. Some of these methods have tests [here](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/SetKeyEventTests.cpp). +[This namespace](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/Helpers.cpp) has any methods which are used across either UI or the backend which aren't specific to either. Some of these methods have tests in [`SetKeyEventTests.cpp`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/KeyboardManagerEngineTest/SetKeyEventTests.cpp). ### Foreground App Detection [`GetCurrentApplication`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L226-L268) is used for detecting the foreground process for App-specific shortcuts. The logic is very similar to that used for FZ's app exception feature, involving `GetForegroundWindow` and `get_process_path`. The one additional case which has been added is for full-screen UWP apps, where the above method fails and returns `ApplicationFrameHost.exe`. The [`GetFullscreenUWPWindowHandle`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L210-L224) uses `GetGUIThreadInfo` API to find the window linked to the GUI thread. This logic is based on [this stackoverflow answer](https://stackoverflow.com/questions/39702704/connecting-uwp-apps-hosted-by-applicationframehost-to-their-real-processes/55353165#55353165). diff --git a/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md b/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md index a94c9f0b36d3..a1e67c292056 100644 --- a/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md +++ b/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md @@ -23,7 +23,7 @@ The KBM UI was originally implemented as a XAML Island, but in order to easily s 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 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). +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 [[Keyboard Manager] Modernize the editor UI - PR#28473](https://github.com/microsoft/PowerToys/pull/28473). [**Link to the original documentation**](https://github.com/microsoft/PowerToys/blob/b3f27057d43445abc59aa04405f7c24bb895a61c/doc/devdocs/modules/keyboardmanager/keyboardmanagerui.md#c-xaml-islands) @@ -43,7 +43,7 @@ When the `EditKeyboardWindow`/`EditShortcutsWindow` is created, [we iterate thro ### OK and Cancel button [On pressing the OK button](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L66-L89) in `EditKeyboardWindow`, first the [`CheckIfRemappingsAreValid` method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L10-L44) is executed which performs basic validity checks on the current remappings in the remap buffer (`static SingleKeyRemapControl::singleKeyRemapBuffer`), such as if there are no NULL columns and none of the source keys are repeated. All other validity checks are assumed to happen while the user adds the remapping. If this is found to be invalid a ContentDialog is displayed which shows that some remappings are invalid and if the user proceeds only the valid ones will be applied. If it is valid [`GetOrphanedKeys`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L46-L75) is executed which checks if any keys are orphaned (i.e. the key has been remapped and no other key has been remapped to it, so there is no way to send that key code), and a dialog is shown for notifying the user with a list of orphaned keys. After this the settings are [applied by adding it to the `KeyboardManagerState.singleKeyReMap` member](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L102-L164) and they are saved to the JSON file. `EditShortcutsWindow` differs slightly from this, as there is no orphaned keys check, and [on pressing OK](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditShortcutsWindow.cpp#L32-L47) both the global and app-specific shortcuts are validated and [updated](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L166-L223). -The code used for updating the remapping tables in `KeyboardManagerState` can be found [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyboardManagerState.cpp#L104-L183). For shortcut remaps, the `sortedKeys` vectors are updated and re-sorted whenever an element is added to them (like [this](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyboardManagerState.cpp#L135-L136)). +The code used for updating the remapping tables in `KeyboardManagerState` can be found in [KeyboardManagerState.cpp lines 104-183](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyboardManagerState.cpp#L104-L183). For shortcut remaps, the `sortedKeys` vectors are updated and re-sorted whenever an element is added to them (like [this code in `KeyboardManagerState::AddOSLevelShortcut`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyboardManagerState.cpp#L135-L136)). On pressing OK (after confirmation dialogs) or Cancel, the window is closed and UI states are reset. @@ -106,4 +106,9 @@ Unlike the Single Key handler, there is a different set of errors that can occur **Note:** After updating the buffer we have [code to handle a special case](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp#L269-L279), which was required to prevent scenarios where a drop down can get deleted but the corresponding `KeyDropDownControl` object isn't deleted. The code checks if the drop down is still linked to the parent and accordingly deletes the `KeyDropDownControl` object from the vector. -**IgnoreKeyToShortcutWarning special case:** [An additional](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp#L177-L181) check was added to ignore the Map to Same key error when an existing remapping is loaded. This was because a remapping like Ctrl->Ctrl+A has an intermediate step of Ctrl->Ctrl, which could lead to an error of invalid input, even though Ctrl+A is valid. The only way to actually add this is from the Type button or by adding them in a different order (like typing Shift+A and then changing Shift to Ctrl). Since the intermediate check could fail, this was causing the app to crash since the Xaml Island wouldn't be completely loaded at that point and the Flyout can't be displayed. [This](https://github.com/microsoft/PowerToys/issues/6695) is the linked issue which describes the repro scenario. +**IgnoreKeyToShortcutWarning special case:** +[An additional](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp#L177-L181) check was added to ignore the Map to Same key error when an existing remapping is loaded. +This was because a remapping like Ctrl->Ctrl+A has an intermediate step of Ctrl->Ctrl, which could lead to an error of invalid input, even though Ctrl+A is valid. +The only way to actually add this is from the Type button or by adding them in a different order (like typing Shift+A and then changing Shift to Ctrl). +Since the intermediate check could fail, this was causing the app to crash since the Xaml Island wouldn't be completely loaded at that point and the Flyout can't be displayed. +[Issue #6695](https://github.com/microsoft/PowerToys/issues/6695) is the linked issue which describes the repro scenario. diff --git a/doc/devdocs/modules/launcher/architecture.md b/doc/devdocs/modules/launcher/architecture.md index f0287f56dca7..1d96edb20f09 100644 --- a/doc/devdocs/modules/launcher/architecture.md +++ b/doc/devdocs/modules/launcher/architecture.md @@ -16,7 +16,7 @@ PowerToys Run UI is written in the WPF framework. The UI code is present in the 3. **[`ResultList.xaml`](/src/modules/launcher/PowerLauncher/LauncherControl.xaml)**: This control implements the UI component for displaying results (marked in green in Fig 1). It consists of a `ListView` WPF control with a custom `ItemTemplate` to display application logo, name, tooltip text, and context menu. ## Data flow -The backend code is written using the `Model-View-ViewModel (MVVM)` structural design pattern. Plugins act as `Model` in this project. A detailed overview of the project's structure is given [here](/doc/devdocs/modules/launcher/project_structure.md). +The backend code is written using the `Model-View-ViewModel (MVVM)` structural design pattern. Plugins act as `Model` in this project. A detailed overview of the project's structure is given in [Project Structure](/doc/devdocs/modules/launcher/project_structure.md). #### Flow of data between UI(view) and ViewModels Data flow between View and ViewModel follows typical `MVVM` scheme. Properties in viewModels are bound to WPF controls and when these properties are updated, `INotifyPropertyChanged` handler is invoked, which in turn updates UI. The diagram below provides a rough sketch of the components involved. diff --git a/doc/devdocs/modules/launcher/new-plugin-checklist.md b/doc/devdocs/modules/launcher/new-plugin-checklist.md index 7287e4305e6c..e1bb7fae098e 100644 --- a/doc/devdocs/modules/launcher/new-plugin-checklist.md +++ b/doc/devdocs/modules/launcher/new-plugin-checklist.md @@ -16,7 +16,7 @@ "Author": string, "Version": "1.0.0", // For future compatibility "Language": "csharp", // So far we support only csharp - "Website": "https://aka.ms/powertoys", + "Website": "https://aka.ms/powertoys", // Has to be an absolute uri starting with "http://" or "https://". "ExecuteFileName": string, // Should be {Type}.PowerToys.Run.Plugin.{PluginName}.dll "IcoPathDark": string, // Path to dark theme icon. The path is relative to the root plugin folder "IcoPathLight": string // Path to light theme icon. The path is relative to the root plugin folder @@ -42,3 +42,4 @@ In the PR that adds a new plugin, reference a new issue to track the work for fu - [ ] Add the resource folder to https://github.com/microsoft/PowerToys/blob/21247c0bb09a1bee3d14d6efa53d0c247f7236af/installer/PowerToysSetup/Product.wxs#L825 - [ ] Add the resource files under the section https://github.com/microsoft/PowerToys/blob/21247c0bb09a1bee3d14d6efa53d0c247f7236af/installer/PowerToysSetup/Product.wxs#L882 +- [ ] Your plugin's executable file (DLL) has to have correct version informations after building it. (This version information will be shown on the settings page.) diff --git a/doc/devdocs/modules/launcher/plugins/community.valuegenerator.md b/doc/devdocs/modules/launcher/plugins/community.valuegenerator.md index 4a580f090d0e..9b94ae78f29e 100644 --- a/doc/devdocs/modules/launcher/plugins/community.valuegenerator.md +++ b/doc/devdocs/modules/launcher/plugins/community.valuegenerator.md @@ -1,6 +1,6 @@ # Value Generator Plugin -The Value Generator plugin is used to generate hashes for strings, to calculate base64 encodings, escape and encode URLs/URIs and to generate GUIDs versions 1, 3, 4 and 5. +The Value Generator plugin is used to generate hashes for strings, to calculate base64 encodings, escape and encode URLs/URIs and to generate GUIDs of version 1, 3, 4, 5, and 7. ![Image of Value Generator plugin](/doc/images/launcher/plugin/community.valuegenerator.png) @@ -34,7 +34,10 @@ The Value Generator plugin is used to generate hashes for strings, to calculate ### [`GUIDGenerator`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDGenerator.cs) - Utility class for generating or calculating GUIDs -- Generating GUID versions 1 and 4 is done using builtin APIs. [`UuidCreateSequential`](https://learn.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-uuidcreatesequential) for version 1 and `System.Guid.NewGuid()` for version 4 +- Generating GUID versions 1, 4, and 7 is done using builtin APIs: + - [`UuidCreateSequential`](https://learn.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-uuidcreatesequential) for version 1 + - `System.Guid.NewGuid()` for version 4 + - `System.Guid.CreateVersion7()` for version 7 - Versions 3 and 5 take two parameters, a namespace and a name - The namespace must be a valid GUID or one of the [predefined ones](https://datatracker.ietf.org/doc/html/rfc4122#appendix-C) - The `PredefinedNamespaces` dictionary contains aliases for the predefined namespaces diff --git a/doc/devdocs/modules/launcher/plugins/history.md b/doc/devdocs/modules/launcher/plugins/history.md index bf62a34b5fd2..0855b39157e7 100644 --- a/doc/devdocs/modules/launcher/plugins/history.md +++ b/doc/devdocs/modules/launcher/plugins/history.md @@ -96,7 +96,7 @@ The plugin uses only these interfaces (all inside the `Main.cs`): #### Build Dependency Access to PluginManager was needed to make this plugin work. Because of this a reference to PowerToys.PowerLauncher was needed. -Since History Plugin needs a reference to PowerToys.PowerLauncher, it can not be set as a dependency reference in PowerToys.PowerLauncher project (else a circular reference would exist). +Since History Plugin needs a reference to PowerToys.PowerLauncher, it cannot be set as a dependency reference in PowerToys.PowerLauncher project (else a circular reference would exist). This means that if you build PowerToys.PowerLauncher only it will not build History Plugin. You will need to manually build History Plugin at least once and again manually if you change it. ### Caching diff --git a/doc/devdocs/modules/launcher/plugins/overview.md b/doc/devdocs/modules/launcher/plugins/overview.md index 2dec6931e213..f715447a0efc 100644 --- a/doc/devdocs/modules/launcher/plugins/overview.md +++ b/doc/devdocs/modules/launcher/plugins/overview.md @@ -32,7 +32,7 @@ Each plugin implements the `IPlugin` interface which comprises of the `Init()` a ### Score - The user query is executed against each of the plugins and the result list view is updated with results from each of the plugins. - The ordering of the results is based on the `Score` of each Result. -- Each plugin assigns a score to a result based on it's relevance. The results with higher scores are displayed higher in the list view and vice versa. +- Each plugin assigns a score to a result based on its relevance. The results with higher scores are displayed higher in the list view and vice versa. ## Plugin settings Plugin settings that are editable from the settings are stored in `PowerToys Run\settings.json`. In the very first run, those settings are populated from plugin' `plugin.json` file. Unlike Wox we do not support multiple action keywords. Instead, we have `ActionKeyword` and `IsGlobal` options. diff --git a/doc/devdocs/modules/launcher/plugins/program.md b/doc/devdocs/modules/launcher/plugins/program.md index 1c3d86ba07cd..9ef8bd82c764 100644 --- a/doc/devdocs/modules/launcher/plugins/program.md +++ b/doc/devdocs/modules/launcher/plugins/program.md @@ -23,7 +23,7 @@ There are broadly two different categories of applications: 5. Common start menu (Applications which are common to all users) 8. Locations pointed to by the PATH environment variable. - To prevent applications and shortcuts present in multiple locations from showing up as duplicate results, we consider apps with the same name, executable name and full path to be the same. -- The subtitle of the application result is set based on it's application type. It could be one of the following: +- The subtitle of the application result is set based on its application type. It could be one of the following: 1. Lnk Shortcuts 2. Appref files 3. Internet shortcut - steam and epic games diff --git a/doc/devdocs/modules/launcher/plugins/windowwalker.md b/doc/devdocs/modules/launcher/plugins/windowwalker.md index 6a26f54e6fdd..c451d8103ae8 100644 --- a/doc/devdocs/modules/launcher/plugins/windowwalker.md +++ b/doc/devdocs/modules/launcher/plugins/windowwalker.md @@ -36,7 +36,7 @@ The user can switch to the found windows, close them or kill their process. | `SubtitleShowPid` | `false` | Show process id in subtitle | | `SubtitleShowDesktopName` | `true` | Show desktop name in subtitle (If two or more desktops exist) | | `ConfirmKillProcess` | `true` | Request confirmation when killing a process | - | `KillProcessTree` | `false` | Kill process and it's child processes | + | `KillProcessTree` | `false` | Kill process and its child processes | | `OpenAfterKillAndClose` | `false` | Stay open after closing windows and killing processes (Not working with kill process confirmation) | | `HideKillProcessOnElevatedProcesses` | `false` | Hide "kill process" button if additional permissions required | | `HideExplorerSettingInfo` | `false` | Hide Explorer process information | diff --git a/doc/devdocs/modules/launcher/project_structure.md b/doc/devdocs/modules/launcher/project_structure.md index 0a8ccbfe3cff..b8edfb71d550 100644 --- a/doc/devdocs/modules/launcher/project_structure.md +++ b/doc/devdocs/modules/launcher/project_structure.md @@ -10,7 +10,7 @@ Fig 1. Project along with their dependencies in `PowerToys Run` ecosystem. This is the startup project for the `PowerToys Run.` It is a WPF desktop application and follows the `Model-View-ViewModel (MVVM)` design pattern. Plugins play the role of `Model` and provide data to `ViewModel.` #### [`PowerLauncher.Telemetry`](/src/modules/launcher/PowerLauncher.Telemetry) -[`PowerLauncher.Telemetry`](/src/modules/launcher/PowerLauncher.Telemetry) is a .net core project that contains telemetry events generated by `PowerLauncher.` These events have been discussed in detail [here](/doc/devdocs/modules/launcher/telemetry.md). +[`PowerLauncher.Telemetry`](/src/modules/launcher/PowerLauncher.Telemetry) is a .net core project that contains telemetry events generated by `PowerLauncher.` These events have been discussed in detail in [Launcher Telemetry](/doc/devdocs/modules/launcher/telemetry.md). #### [`Wox.Core`](/src/modules/launcher/Wox.Core) [`Wox.Core`](/src/modules/launcher/Wox.Core) is a .net core project that contains helper classes required by the `PowerLauncher` project. Two major functionalities encapsulated in this project are [`PluginManager`](/src/modules/launcher/Wox.Core/Plugin/PluginManager.cs) and [`Query Builder.`](/src/modules/launcher/Wox.Core/Plugin/QueryBuilder.cs) [`PluginManager`](/src/modules/launcher/Wox.Core/Plugin/PluginManager.cs) provides an interface for managing C# plugins. [`Query Builder.`](/src/modules/launcher/Wox.Core/Plugin/QueryBuilder.cs) decimate user-typed query string and creates a [`Query`](/src/modules/launcher/Wox.Plugin/Query.cs) object. [`Query`](/src/modules/launcher/Wox.Plugin/Query.cs) object contains the action keyword and cleaned query, which is then sent to all plugins. @@ -19,6 +19,6 @@ This is the startup project for the `PowerToys Run.` It is a WPF desktop applica [`Wox.Infrastructure`](/src/modules/launcher/Wox.Infrastructure) is a .net core project that contains helper classes required for image manipulation and storage by the `PowerLauncher` project and the plugins. [`ImageLoader.cs`](/src/modules/launcher/Wox.Infrastructure/Image/ImageLoader.cs) class is used to load icons for `Win32` program. It also provides caching functionality to speed up image loading for frequently queried programs. #### [`Wox.Plugin`](/src/modules/launcher/Wox.Plugin) -[`Wox.Plugin`](/src/modules/launcher/Wox.Plugin) contains interfaces that facilitate communication between `PowerLauncher` and plugins. These interfaces have been discussed in detail [here](/doc/devdocs/modules/launcher/architecture.md#flow-of-data-between-viewmodels-and-pluginsmodel). It also contains a helper class for logging. [`Log.cs`](/src/modules/launcher/Wox.Plugin/Logger/Log.cs) provides an abstraction for logging error, information, and output to text files. These files are stored at `%userprofile%/appdata/local/microsoft/powertoys/powertoys run/Logs.` +[`Wox.Plugin`](/src/modules/launcher/Wox.Plugin) contains interfaces that facilitate communication between `PowerLauncher` and plugins. These interfaces have been discussed in detail in [Flow of data between ViewModels and Plugins(Model)](/doc/devdocs/modules/launcher/architecture.md#flow-of-data-between-viewmodels-and-pluginsmodel). It also contains a helper class for logging. [`Log.cs`](/src/modules/launcher/Wox.Plugin/Logger/Log.cs) provides an abstraction for logging error, information, and output to text files. These files are stored at `%userprofile%/appdata/local/microsoft/powertoys/powertoys run/Logs.` diff --git a/doc/devdocs/modules/launcher/readme.md b/doc/devdocs/modules/launcher/readme.md index 75b62ecb3c35..984d82833c6f 100644 --- a/doc/devdocs/modules/launcher/readme.md +++ b/doc/devdocs/modules/launcher/readme.md @@ -1,19 +1,24 @@ # Table of Contents 1. [Architecture](/doc/devdocs/modules/launcher/architecture.md) 2. [Debugging](/doc/devdocs/modules/launcher/debugging.md) -3. [Project Structure](/doc/devdocs/modules/launcher/project_structure.md) -4. [Telemetry](/doc/devdocs/modules/launcher/telemetry.md) -5. Plugins +3. [New Plugin Checklist](/doc/devdocs/modules/launcher/new-plugin-checklist.md) +4. [Project Structure](/doc/devdocs/modules/launcher/project_structure.md) +5. [Telemetry](/doc/devdocs/modules/launcher/telemetry.md) +6. Plugins - [Overview](/doc/devdocs/modules/launcher/plugins/overview.md) - [Calculator](/doc/devdocs/modules/launcher/plugins/calculator.md) - [Folder](/doc/devdocs/modules/launcher/plugins/folder.md) + - [History](/doc/devdocs/modules/launcher/plugins/history.md) - [Indexer](/doc/devdocs/modules/launcher/plugins/indexer.md) - [OneNote](/doc/devdocs/modules/launcher/plugins/onenote.md) - [Program](/doc/devdocs/modules/launcher/plugins/program.md) - [Registry](/doc/devdocs/modules/launcher/plugins/registry.md) - [Shell](/doc/devdocs/modules/launcher/plugins/shell.md) - [Time and Date](/doc/devdocs/modules/launcher/plugins/timedate.md) - - [Windows System Commands](/doc/devdocs/modules/launcher/plugins/system.md) + - [Unit Converter](/doc/devdocs/modules/launcher/plugins/community.unitconverter.md) - [Uri](/doc/devdocs/modules/launcher/plugins/uri.md) - - [Window Walker](/doc/devdocs/modules/launcher/plugins/windowwalker.md) + - [Value Generator](/doc/devdocs/modules/launcher/plugins/community.valuegenerator.md) - [Web Search](/doc/devdocs/modules/launcher/plugins/WebSearch.md) + - [Windows Settings](/doc/devdocs/modules/launcher/plugins/windowssettings.md) + - [Windows System Commands](/doc/devdocs/modules/launcher/plugins/system.md) + - [Window Walker](/doc/devdocs/modules/launcher/plugins/windowwalker.md) diff --git a/doc/devdocs/readme.md b/doc/devdocs/readme.md index 558cb5aa4962..50912c5b3fe1 100644 --- a/doc/devdocs/readme.md +++ b/doc/devdocs/readme.md @@ -73,7 +73,6 @@ The installer can only be compiled in `Release` mode; steps 1 and 2 must be perf 1. Compile `PowerToys.sln`. Instructions are listed above. 1. Compile `BugReportTool.sln` tool. Path from root: `tools\BugReportTool\BugReportTool.sln` (details listed below) -1. Compile `WebcamReportTool.sln` tool. Path from root: `tools\WebcamReportTool\WebcamReportTool.sln` (details listed below) 1. Compile `StylesReportTool.sln` tool. Path from root: `tools\StylesReportTool\StylesReportTool.sln` (details listed below) 1. Compile `PowerToysSetup.sln` Path from root: `installer\PowerToysSetup.sln` (details listed below) @@ -95,9 +94,6 @@ The installer can only be compiled in `Release` mode; steps 1 and 2 must be perf nuget restore .\tools\BugReportTool\BugReportTool.sln msbuild -p:Platform=x64 -p:Configuration=Release .\tools\BugReportTool\BugReportTool.sln -nuget restore .\tools\WebcamReportTool\WebcamReportTool.sln -msbuild -p:Platform=x64 -p:Configuration=Release .\tools\WebcamReportTool\WebcamReportTool.sln - nuget restore .\tools\StylesReportTool\StylesReportTool.sln msbuild -p:Platform=x64 -p:Configuration=Release .\tools\StylesReportTool\StylesReportTool.sln ``` @@ -109,9 +105,6 @@ If you prefer, you can alternatively build prerequisite projects for the install 1. Open `tools\BugReportTool\BugReportTool.sln` 1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` 1. From the `Build` menu, choose `Build Solution`. -1. Open `tools\WebcamReportTool\WebcamReportTool.sln` -1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` -1. From the `Build` menu, choose `Build Solution`. 1. Open `tools\StylesReportTool\StylesReportTool.sln` 1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` 1. From the `Build` menu, choose `Build Solution`. diff --git a/doc/devdocs/runner.md b/doc/devdocs/runner.md index dab6fc8eb14a..f4e5ebb1e2dd 100644 --- a/doc/devdocs/runner.md +++ b/doc/devdocs/runner.md @@ -5,7 +5,7 @@ Contains the executable starting point, initialization code and the list of know Contains code for initializing and managing the PowerToy modules. `PowertoyModule` is a RAII-style holder for the `PowertoyModuleIface` pointer, which we got by [invoking module DLL's `powertoy_create` function](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/powertoy_module.cpp#L13-L24). #### [`powertoys_events.cpp`](/src/runner/powertoys_events.cpp) -Contains code that handles the various events listeners, and forwards those events to the PowerToys modules. You can learn more about the current event architecture [here](/doc/devdocs/shared-hooks.md). +Contains code that handles the various events listeners, and forwards those events to the PowerToys modules. You can learn more about the current event architecture in [shared hooks](/doc/devdocs/shared-hooks.md). #### [`lowlevel_keyboard_event.cpp`](/src/runner/lowlevel_keyboard_event.cpp) Contains code for registering the low level keyboard event hook that listens for keyboard events. Please note that `signal_event` is called from the main thread for this event. diff --git a/doc/devdocs/settingsv2/communication-with-modules.md b/doc/devdocs/settingsv2/communication-with-modules.md index a19190fbe740..d4b2a3c89688 100644 --- a/doc/devdocs/settingsv2/communication-with-modules.md +++ b/doc/devdocs/settingsv2/communication-with-modules.md @@ -6,7 +6,7 @@ ## PT Run - Any changes to the UI are saved by the settings process in the `settings.json` file located within the `/Local/Microsoft/PowerToys/Launcher/` folder. -- PT Run watches for any changes within this file and updates it's general settings or propagates the information to the plugins, depending on the type of information. +- PT Run watches for any changes within this file and updates its general settings or propagates the information to the plugins, depending on the type of information. Eg: The maximum number of results drop down updates the maximum number of rows in the results list which updates the general settings of PT Run whereas the drive detection checkbox details are dispatched to the indexer plugin. ## Keyboard Manager diff --git a/doc/devdocs/settingsv2/project-overview.md b/doc/devdocs/settingsv2/project-overview.md index d196aafe83f7..50b15f4e7407 100644 --- a/doc/devdocs/settingsv2/project-overview.md +++ b/doc/devdocs/settingsv2/project-overview.md @@ -1,5 +1,5 @@ # Overview -`Settings` is Windows App Sdk WinUI3 .Net Unpackaged desktop application. More details about Windows App Sdk can be found [here](https://github.com/microsoft/WindowsAppSDK#windows-app-sdk---calling-all-windows-developers). More details about WinUI can be found [here](https://microsoft.github.io/microsoft-ui-xaml/about.html#what-is-it). +`Settings` is Windows App Sdk WinUI3 .Net Unpackaged desktop application. More details about Windows App Sdk can be found in [Windows App SDK - Calling all Windows developers!](https://github.com/microsoft/WindowsAppSDK#windows-app-sdk---calling-all-windows-developers). More details about WinUI can be found in [Build apps with WinUI](https://developer.microsoft.com/en-us/windows/develop/). ## Settings V2 Project structure The Settings project .Net WinUI3 based project which diff --git a/doc/devdocs/tools/build-tools.md b/doc/devdocs/tools/build-tools.md index dfa4e251b20d..b8acaa3273d1 100644 --- a/doc/devdocs/tools/build-tools.md +++ b/doc/devdocs/tools/build-tools.md @@ -25,7 +25,3 @@ This script is used by the pipeline to move the .resw files to the correct locat ## [versionSetting.ps1](/tools/build/versionSetting.ps1) Sets `version.props` file with the version number. - -## [video_conference_make_cab.ps1](/tools/build/video_conference_make_cab.ps1) - -This script creates a cab file for the Video Conference Mute driver. diff --git a/doc/devdocs/tools/readme.md b/doc/devdocs/tools/readme.md index 1bf19d610b55..a2640bda7a97 100644 --- a/doc/devdocs/tools/readme.md +++ b/doc/devdocs/tools/readme.md @@ -18,4 +18,3 @@ Following tools are currently available: * [project template](/tools/project_template/README.md) - A Visual Studio project template for a new PowerToys project. * [StylesReportTool](styles-report-tool.md) - A tool to collect information about an open window. * [Verification scripts](verification-scripts.md) - A set of scripts that help verifying the PowerToys installation. -* [WebcamReportTool](webcam-report-tool.md) - A tool to collect information about the connected webcams. diff --git a/doc/devdocs/tools/webcam-report-tool.md b/doc/devdocs/tools/webcam-report-tool.md deleted file mode 100644 index efa6d47da3ee..000000000000 --- a/doc/devdocs/tools/webcam-report-tool.md +++ /dev/null @@ -1,6 +0,0 @@ -# [WebcamReportTool](/tools/WebcamReportTool/) - -This command line application generates a report about the connected webcams on the desktop called "WebcamReport.txt". The report contains the following information about every webcam: - -* Name -* Supported formats diff --git a/doc/images/icons/Advanced.png b/doc/images/icons/Advanced.png new file mode 100644 index 000000000000..f01ca889eea2 Binary files /dev/null and b/doc/images/icons/Advanced.png differ diff --git a/doc/images/icons/NewPlus.png b/doc/images/icons/NewPlus.png new file mode 100644 index 000000000000..aad1984ed43c Binary files /dev/null and b/doc/images/icons/NewPlus.png differ diff --git a/doc/images/icons/WindowingAndLayouts.png b/doc/images/icons/WindowingAndLayouts.png new file mode 100644 index 000000000000..868176a2c82b Binary files /dev/null and b/doc/images/icons/WindowingAndLayouts.png differ diff --git a/doc/images/overview/MeasureTool_large.png b/doc/images/overview/MeasureTool_large.png index 5484756fb0da..d7e6b5b0f1ec 100644 Binary files a/doc/images/overview/MeasureTool_large.png and b/doc/images/overview/MeasureTool_large.png differ diff --git a/doc/images/overview/MeasureTool_small.png b/doc/images/overview/MeasureTool_small.png index 070d159c3613..10b6fe6992f2 100644 Binary files a/doc/images/overview/MeasureTool_small.png and b/doc/images/overview/MeasureTool_small.png differ diff --git a/doc/images/overview/Original/VideoConference.png b/doc/images/overview/Original/VideoConference.png deleted file mode 100644 index 3a71531361c3..000000000000 Binary files a/doc/images/overview/Original/VideoConference.png and /dev/null differ diff --git a/doc/images/overview/VideoConference_large.png b/doc/images/overview/VideoConference_large.png deleted file mode 100644 index 028d98889c62..000000000000 Binary files a/doc/images/overview/VideoConference_large.png and /dev/null differ diff --git a/doc/images/overview/VideoConference_small.png b/doc/images/overview/VideoConference_small.png deleted file mode 100644 index 8e2030e92d63..000000000000 Binary files a/doc/images/overview/VideoConference_small.png and /dev/null differ diff --git a/doc/planning/awake.md b/doc/planning/awake.md index ae01e6f85db5..d6ccd6808f39 100644 --- a/doc/planning/awake.md +++ b/doc/planning/awake.md @@ -10,8 +10,9 @@ The build ID can be found in `Core\Constants.cs` in the `BuildId` variable - it The build ID moniker is made up of two components - a reference to a [Halo](https://en.wikipedia.org/wiki/Halo_(franchise)) character, and the date when the work on the specific build started in the format of `MMDDYYYY`. -| Build ID | Build Date | +| Build ID | Build Date | |:-------------------------------------------------------------------|:------------------| +| [`TILLSON_11272024`](#TILLSON_11272024-november-27-2024) | November 27, 2024 | | [`PROMETHEAN_09082024`](#PROMETHEAN_09082024-september-8-2024) | September 8, 2024 | | [`VISEGRADRELAY_08152024`](#VISEGRADRELAY_08152024-august-15-2024) | August 15, 2024 | | [`DAISY023_04102024`](#DAISY023_04102024-april-10-2024) | April 10, 2024 | @@ -19,13 +20,28 @@ The build ID moniker is made up of two components - a reference to a [Halo](http | [`LIBRARIAN_03202022`](#librarian_03202022-march-20-2022) | March 20, 2022 | | `ARBITER_01312022` | January 31, 2022 | +### `TILLSON_11272024` (November 27, 2024) + +>[!NOTE] +>See pull request: [Awake - `TILLSON_11272024`](https://github.com/microsoft/PowerToys/pull/36049) + +- [#35250](https://github.com/microsoft/PowerToys/issues/35250) Updates the icon retry policy, making sure that the icon consistently and correctly renders in the tray. +- [#35848](https://github.com/microsoft/PowerToys/issues/35848) Fixed a bug where custom tray time shortcuts for longer than 24 hours would be parsed as zero hours/zero minutes. +- [#34716](https://github.com/microsoft/PowerToys/issues/34716) Properly recover the state icon in the tray after an `explorer.exe` crash. +- Added configuration safeguards to make sure that invalid values for timed keep-awake times do not result in exceptions. +- Updated the tray initialization logic, making sure we wait for it to be properly created before setting icons. +- Expanded logging capabilities to track invoking functions. +- Added command validation logic to make sure that incorrect command line arguments display an error. +- Display state now shown in the tray tooltip. +- When timed mode is used, changing the display setting will no longer reset the timer. + ### `PROMETHEAN_09082024` (September 8, 2024) >[!NOTE] >See pull request: [Awake - `PROMETHEAN_09082024`](https://github.com/microsoft/PowerToys/pull/34717) - Updating the initialization logic to make sure that settings are respected for proper group policy and single-instance detection. -- [#34148] Fixed a bug from the previous release that incorrectly synchronized threads for shell icon creation and initialized parent PID when it was not parented. +- [#34148](https://github.com/microsoft/PowerToys/issues/34148) Fixed a bug from the previous release that incorrectly synchronized threads for shell icon creation and initialized parent PID when it was not parented. ### `VISEGRADRELAY_08152024` (August 15, 2024) diff --git a/doc/thirdPartyRunPlugins.md b/doc/thirdPartyRunPlugins.md index ad9b417b3952..7e59e3acd496 100644 --- a/doc/thirdPartyRunPlugins.md +++ b/doc/thirdPartyRunPlugins.md @@ -39,6 +39,9 @@ Contact the developers of a plugin directly for assistance with a specific plugi | [GitHubRepo](https://github.com/8LWXpg/PowerToysRun-GitHubRepo) | [8LWXpg](https://github.com/8LWXpg) | Search and open GitHub repositories | | [ProcessKiller](https://github.com/8LWXpg/PowerToysRun-ProcessKiller) | [8LWXpg](https://github.com/8LWXpg) | Search and kill processes | | [ChatGPT](https://github.com/ferraridavide/ChatGPTPowerToys) | [ferraridavide](https://github.com/ferraridavide) | Ask a question to ChatGPT | +| [CanIUse](https://github.com/skttl/ptrun-caniuse) | [skttl](https://github.com/skttl) | Look up browser feature support with caniuse.com | +| [TailwindCSS](https://github.com/skttl/ptrun-tailwindcss) | [skttl](https://github.com/skttl) | Search the documentation of TailwindCSS | +| [HttpStatusCodes](https://github.com/grzhan/HttpStatusCodePowerToys) | [grzhan](https://github.com/grzhan) | Search for http status codes | ## Extending software plugins @@ -58,3 +61,4 @@ Below are community created plugins that target a website or software. They are | [PowerSearch for 1Password](https://github.com/KairuDeibisu/PowerToysRunPlugin1Password) | [KairuDeibisu](https://github.com/KairuDeibisu) | An unofficial plugin for searching 1Password for usernames and passwords | | [HackMD](https://github.com/8LWXpg/PowerToysRun-HackMD) | [8LWXpg](https://github.com/8LWXpg) | Open HackMD notes | | [SSH](https://github.com/8LWXpg/PowerToysRun-SSH) | [8LWXpg](https://github.com/8LWXpg) | Connect to ssh clients | +| [Bilibili](https://github.com/Whuihuan/PowerToysRun-Bilibili) | [Whuihuan](https://github.com/Whuihuan) | Use AVID or BVID to parse and jump to Bilibili | diff --git a/installer/PowerToysSetup/Common.wxi b/installer/PowerToysSetup/Common.wxi index f036b3797b8a..21855a79363a 100644 --- a/installer/PowerToysSetup/Common.wxi +++ b/installer/PowerToysSetup/Common.wxi @@ -8,7 +8,6 @@ - diff --git a/installer/PowerToysSetup/NewPlus.wxs b/installer/PowerToysSetup/NewPlus.wxs index 80fd5a94f4e2..4dd1c677010e 100644 --- a/installer/PowerToysSetup/NewPlus.wxs +++ b/installer/PowerToysSetup/NewPlus.wxs @@ -18,6 +18,19 @@ + + + + + + + + + + + + + @@ -27,6 +40,7 @@ + diff --git a/installer/PowerToysSetup/PowerToysInstaller.wixproj b/installer/PowerToysSetup/PowerToysInstaller.wixproj index 8771920c3cd8..7ce39b82cfa7 100644 --- a/installer/PowerToysSetup/PowerToysInstaller.wixproj +++ b/installer/PowerToysSetup/PowerToysInstaller.wixproj @@ -51,7 +51,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil call move /Y ..\..\..\Settings.wxs.bk ..\..\..\Settings.wxs call move /Y ..\..\..\ShortcutGuide.wxs.bk ..\..\..\ShortcutGuide.wxs call move /Y ..\..\..\Tools.wxs.bk ..\..\..\Tools.wxs - call move /Y ..\..\..\VideoConference.wxs.bk ..\..\..\VideoConference.wxs call move /Y ..\..\..\WinAppSDK.wxs.bk ..\..\..\WinAppSDK.wxs call move /Y ..\..\..\WinUI3Applications.wxs.bk ..\..\..\WinUI3Applications.wxs call move /Y ..\..\..\Workspaces.wxs.bk ..\..\..\Workspaces.wxs @@ -119,7 +118,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil - diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index 7a3a6ee69730..33dc8d0e550e 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -69,7 +69,6 @@ - @@ -196,6 +195,9 @@ NOT Installed + + NOT Installed + + + - - - - - - @@ -34,7 +28,6 @@ - diff --git a/installer/PowerToysSetup/VideoConference.wxs b/installer/PowerToysSetup/VideoConference.wxs deleted file mode 100644 index 04bdb1e5066e..000000000000 --- a/installer/PowerToysSetup/VideoConference.wxs +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - WINDOWSBUILDNUMBER >= 19041 - - - - - - - - - - - - - WINDOWSBUILDNUMBER >= 19041 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/installer/PowerToysSetup/generateAllFileComponents.ps1 b/installer/PowerToysSetup/generateAllFileComponents.ps1 index 50ce0f2dd641..3592b14362ba 100644 --- a/installer/PowerToysSetup/generateAllFileComponents.ps1 +++ b/installer/PowerToysSetup/generateAllFileComponents.ps1 @@ -30,7 +30,7 @@ Function Generate-FileList() { $fileExclusionList = @("*.pdb", "*.lastcodeanalysissucceeded", "createdump.exe", "powertoys.exe") - $fileInclusionList = @("*.dll", "*.exe", "*.json", "*.msix", "*.png", "*.gif", "*.ico", "*.cur", "*.svg", "index.html", "reg.js", "gitignore.js", "monacoSpecialLanguages.js", "customTokenColors.js", "*.pri") + $fileInclusionList = @("*.dll", "*.exe", "*.json", "*.msix", "*.png", "*.gif", "*.ico", "*.cur", "*.svg", "index.html", "reg.js", "gitignore.js", "srt.js", "monacoSpecialLanguages.js", "customTokenThemeRules.js", "*.pri") $dllsToIgnore = @("System.CodeDom.dll", "WindowsBase.dll") diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp index 8995d2f9b62f..d0aca611fda4 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.cpp +++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp @@ -11,6 +11,7 @@ #include "../../src/common/updating/installer.h" #include "../../src/common/version/version.h" #include "../../src/common/Telemetry/EtwTrace/EtwTrace.h" +#include "../../src/common/utils/clean_video_conference.h" #include #include @@ -328,6 +329,19 @@ UINT __stdcall CheckGPOCA(MSIHANDLE hInstall) return WcaFinalize(er); } +// We've deprecated Video Conference Mute. This Custom Action cleans up any stray registry entry for the driver dll. +UINT __stdcall CleanVideoConferenceRegistryCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + hr = WcaInitialize(hInstall, "CleanVideoConferenceRegistry"); + ExitOnFailure(hr, "Failed to initialize"); + clean_video_conference(); +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + UINT __stdcall ApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall) { HRESULT hr = S_OK; @@ -1026,164 +1040,6 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall) return WcaFinalize(er); } -UINT __stdcall CertifyVirtualCameraDriverCA(MSIHANDLE hInstall) -{ -#ifdef CIBuild // On pipeline we are using microsoft certification - WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA"); - return WcaFinalize(ERROR_SUCCESS); -#else - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - LPWSTR certificatePath = nullptr; - HCERTSTORE hCertStore = nullptr; - HANDLE hfile = nullptr; - DWORD size = INVALID_FILE_SIZE; - char* pFileContent = nullptr; - - hr = WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA"); - ExitOnFailure(hr, "Failed to initialize", hr); - - hr = WcaGetProperty(L"CustomActionData", &certificatePath); - ExitOnFailure(hr, "Failed to get install property", hr); - - hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"AuthRoot"); - if (!hCertStore) - { - hr = GetLastError(); - ExitOnFailure(hr, "Cannot put principal run level: %x", hr); - } - - hfile = CreateFile(certificatePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hfile == INVALID_HANDLE_VALUE) - { - hr = GetLastError(); - ExitOnFailure(hr, "Certificate file open failed", hr); - } - - size = GetFileSize(hfile, nullptr); - if (size == INVALID_FILE_SIZE) - { - hr = GetLastError(); - ExitOnFailure(hr, "Certificate file size not valid", hr); - } - - pFileContent = static_cast(malloc(size)); - - DWORD sizeread; - if (!ReadFile(hfile, pFileContent, size, &sizeread, nullptr)) - { - hr = GetLastError(); - ExitOnFailure(hr, "Certificate file read failed", hr); - } - - if (!CertAddEncodedCertificateToStore(hCertStore, - X509_ASN_ENCODING, - reinterpret_cast(pFileContent), - size, - CERT_STORE_ADD_ALWAYS, - nullptr)) - { - hr = GetLastError(); - ExitOnFailure(hr, "Adding certificate failed", hr); - } - - free(pFileContent); - -LExit: - ReleaseStr(certificatePath); - if (hCertStore) - { - CertCloseStore(hCertStore, 0); - } - if (hfile) - { - CloseHandle(hfile); - } - - if (!SUCCEEDED(hr)) - { - PMSIHANDLE hRecord = MsiCreateRecord(0); - MsiRecordSetString(hRecord, 0, TEXT("Failed to add certificate to store")); - MsiProcessMessage(hInstall, static_cast(INSTALLMESSAGE_WARNING + MB_OK), hRecord); - } - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -#endif -} - -UINT __stdcall InstallVirtualCameraDriverCA(MSIHANDLE hInstall) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - LPWSTR driverPath = nullptr; - - hr = WcaInitialize(hInstall, "InstallVirtualCameraDriverCA"); - ExitOnFailure(hr, "Failed to initialize"); - - hr = WcaGetProperty(L"CustomActionData", &driverPath); - ExitOnFailure(hr, "Failed to get install property"); - - BOOL requiresReboot; - DiInstallDriverW(GetConsoleWindow(), driverPath, DIIRFLAG_FORCE_INF, &requiresReboot); - - hr = GetLastError(); - ExitOnFailure(hr, "Failed to install driver"); - -LExit: - - if (!SUCCEEDED(hr)) - { - PMSIHANDLE hRecord = MsiCreateRecord(0); - MsiRecordSetString(hRecord, 0, TEXT("Failed to install virtual camera driver")); - MsiProcessMessage(hInstall, static_cast(INSTALLMESSAGE_WARNING + MB_OK), hRecord); - } - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - -UINT __stdcall UninstallVirtualCameraDriverCA(MSIHANDLE hInstall) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - LPWSTR driverPath = nullptr; - - hr = WcaInitialize(hInstall, "UninstallVirtualCameraDriverCA"); - ExitOnFailure(hr, "Failed to initialize"); - - hr = WcaGetProperty(L"CustomActionData", &driverPath); - ExitOnFailure(hr, "Failed to get uninstall property"); - - BOOL requiresReboot; - DiUninstallDriverW(GetConsoleWindow(), driverPath, 0, &requiresReboot); - - switch (GetLastError()) - { - case ERROR_ACCESS_DENIED: - case ERROR_FILE_NOT_FOUND: - case ERROR_INVALID_FLAGS: - case ERROR_IN_WOW64: - { - hr = GetLastError(); - ExitOnFailure(hr, "Failed to uninstall driver"); - break; - } - } - -LExit: - - if (!SUCCEEDED(hr)) - { - PMSIHANDLE hRecord = MsiCreateRecord(0); - MsiRecordSetString(hRecord, 0, TEXT("Failed to uninstall virtual camera driver")); - MsiProcessMessage(hInstall, static_cast(INSTALLMESSAGE_WARNING + MB_OK), hRecord); - } - - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - UINT __stdcall UnRegisterContextMenuPackagesCA(MSIHANDLE hInstall) { using namespace winrt::Windows::Foundation; @@ -1272,7 +1128,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall) } processes.resize(bytes / sizeof(processes[0])); - std::array processesToTerminate = { + std::array processesToTerminate = { L"PowerToys.PowerLauncher.exe", L"PowerToys.Settings.exe", L"PowerToys.AdvancedPaste.exe", @@ -1309,6 +1165,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall) L"PowerToys.WorkspacesLauncherUI.exe", L"PowerToys.WorkspacesEditor.exe", L"PowerToys.WorkspacesWindowArranger.exe", + L"PowerToys.ZoomIt.exe", L"PowerToys.exe", }; diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def index f685a0be1dfc..d9ed0d0f04ee 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.def +++ b/installer/PowerToysSetupCustomActions/CustomAction.def @@ -3,6 +3,7 @@ LIBRARY "PowerToysSetupCustomActions" EXPORTS LaunchPowerToysCA CheckGPOCA + CleanVideoConferenceRegistryCA ApplyModulesRegistryChangeSetsCA DetectPrevInstallPathCA RemoveScheduledTasksCA @@ -15,12 +16,9 @@ EXPORTS TelemetryLogRepairCancelCA TelemetryLogRepairFailCA TerminateProcessesCA - CertifyVirtualCameraDriverCA - InstallVirtualCameraDriverCA InstallEmbeddedMSIXCA InstallDSCModuleCA UnApplyModulesRegistryChangeSetsCA - UninstallVirtualCameraDriverCA UnRegisterContextMenuPackagesCA UninstallEmbeddedMSIXCA UninstallDSCModuleCA diff --git a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj index dee9f63e2b97..e2de4a40658b 100644 --- a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj +++ b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj @@ -73,7 +73,6 @@ call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\Settings.wxs"" ""$(ProjectDir)..\PowerToysSetup\Settings.wxs.bk"""" call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\ShortcutGuide.wxs"" ""$(ProjectDir)..\PowerToysSetup\ShortcutGuide.wxs.bk"""" call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\Tools.wxs"" ""$(ProjectDir)..\PowerToysSetup\Tools.wxs.bk"""" - call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\VideoConference.wxs"" ""$(ProjectDir)..\PowerToysSetup\VideoConference.wxs.bk"""" call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\WinAppSDK.wxs"" ""$(ProjectDir)..\PowerToysSetup\WinAppSDK.wxs.bk"""" call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\WinUI3Applications.wxs"" ""$(ProjectDir)..\PowerToysSetup\WinUI3Applications.wxs.bk"""" call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\Workspaces.wxs"" ""$(ProjectDir)..\PowerToysSetup\Workspaces.wxs.bk"""" diff --git a/src/.editorconfig b/src/.editorconfig index 28245c30fc47..c011b4a432b1 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -46,32 +46,28 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case dotnet_naming_symbols.interface.applicable_kinds = interface dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = +dotnet_naming_symbols.interface.required_modifiers = dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = +dotnet_naming_symbols.types.required_modifiers = dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.non_field_members.required_modifiers = # Naming styles dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = -dotnet_naming_style.pascal_case.capitalization = pascal_case dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion @@ -96,4 +92,176 @@ end_of_line = crlf dotnet_diagnostic.IDE0065.severity = none # IDE0009: Add this or Me qualification -dotnet_diagnostic.IDE0009.severity = none \ No newline at end of file +dotnet_diagnostic.IDE0009.severity = none + +# IDE-based code analysis rules +# IDE0005: Remove unnecessary import +dotnet_diagnostic.IDE0005.severity = suggestion + +# IDE0008: Use explicit type instead of 'var' +dotnet_diagnostic.IDE0008.severity = silent + +# IDE0016: Use throw expression +dotnet_diagnostic.IDE0016.severity = suggestion + +# IDE0018: Inline variable declaration +dotnet_diagnostic.IDE0018.severity = suggestion + +# IDE0019: Use pattern matching +dotnet_diagnostic.IDE0019.severity = suggestion + +# IDE0021: Use expression body for constructors +dotnet_diagnostic.IDE0021.severity = silent + +# IDE0022: Use expression body for methods +dotnet_diagnostic.IDE0022.severity = silent + +# IDE0023: Use expression body for conversion operators +dotnet_diagnostic.IDE0023.severity = silent + +# IDE0025: Use expression body for properties +dotnet_diagnostic.IDE0025.severity = silent + +# IDE0027: Use expression body for accessors +dotnet_diagnostic.IDE0027.severity = silent + +# IDE0028: Use collection initializers +dotnet_diagnostic.IDE0028.severity = suggestion + +# IDE0029: Null check can be simplified +dotnet_diagnostic.IDE0029.severity = suggestion + +# IDE0031: Use null propagation +dotnet_diagnostic.IDE0031.severity = suggestion + +# IDE0032: Use auto property +dotnet_diagnostic.IDE0032.severity = suggestion + +# IDE0034: Simplify default expression +dotnet_diagnostic.IDE0034.severity = suggestion + +# IDE0036: Order modifiers +dotnet_diagnostic.IDE0036.severity = suggestion + +# IDE0039: Use local function instead of lambda +dotnet_diagnostic.IDE0039.severity = suggestion + +# IDE0042: Deconstruct variable declaration +dotnet_diagnostic.IDE0042.severity = suggestion + +# IDE0044: Add readonly modifier +dotnet_diagnostic.IDE0044.severity = suggestion + +# IDE0045: Use conditional expression for assignment +dotnet_diagnostic.IDE0045.severity = suggestion + +# IDE0046: Use conditional expression for return +dotnet_diagnostic.IDE0046.severity = suggestion + +# IDE0047: Remove unnecessary parentheses +dotnet_diagnostic.IDE0047.severity = suggestion + +# IDE0051: Remove unused private member +dotnet_diagnostic.IDE0051.severity = suggestion + +# IDE0052: Remove unread private member +dotnet_diagnostic.IDE0052.severity = suggestion + +# IDE0054: Use compound assignment +dotnet_diagnostic.IDE0054.severity = suggestion + +# IDE0055: Fix formatting +dotnet_diagnostic.IDE0055.severity = suggestion + +# IDE0056: Use index operator +dotnet_diagnostic.IDE0056.severity = suggestion + +# IDE0057: Use range operator +dotnet_diagnostic.IDE0057.severity = suggestion + +# IDE0059: Remove unnecessary value assignment +dotnet_diagnostic.IDE0059.severity = suggestion + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = suggestion + +# IDE0061: Use expression body for local functions +dotnet_diagnostic.IDE0061.severity = silent + +# IDE0063: Use simple 'using' statement +dotnet_diagnostic.IDE0063.severity = suggestion + +# IDE0071: Simplify interpolation +dotnet_diagnostic.IDE0071.severity = suggestion + +# IDE0074: Use coalesce compound assignment +dotnet_diagnostic.IDE0074.severity = suggestion + +# IDE0075: Simplify conditional expression +dotnet_diagnostic.IDE0075.severity = suggestion + +# IDE0077: Avoid legacy format target in global 'SuppressMessageAttribute' +dotnet_diagnostic.IDE0077.severity = suggestion + +# IDE0078: Use pattern matching +dotnet_diagnostic.IDE0078.severity = suggestion + +# IDE0083: Use pattern matching ('not' operator) +dotnet_diagnostic.IDE0083.severity = suggestion + +# IDE0090: Simplify 'new' expression +dotnet_diagnostic.IDE0090.severity = suggestion + +# IDE0100: Remove unnecessary equality operator +dotnet_diagnostic.IDE0100.severity = suggestion + +# IDE0130: Namespace does not match folder structure +dotnet_diagnostic.IDE0130.severity = suggestion + +# IDE0160: Use block-scoped namespace +dotnet_diagnostic.IDE0160.severity = silent + +# IDE0180: Use tuple to swap values +dotnet_diagnostic.IDE0180.severity = suggestion + +# IDE0200: Remove unnecessary lambda expression +dotnet_diagnostic.IDE0200.severity = suggestion + +# IDE0240: Nullable directive is redundant +dotnet_diagnostic.IDE0240.severity = suggestion + +# IDE0250: Struct can be made 'readonly' +dotnet_diagnostic.IDE0250.severity = suggestion + +# IDE0251: Member can be made 'readonly'' +dotnet_diagnostic.IDE0251.severity = suggestion + +# IDE0260: Use pattern matching +dotnet_diagnostic.IDE0260.severity = suggestion + +# IDE0270: Null check can be simplified +dotnet_diagnostic.IDE0270.severity = suggestion + +# IDE0290: Use primary constructor +dotnet_diagnostic.IDE0290.severity = silent + +# IDE0300: Use collection expression for array +dotnet_diagnostic.IDE0300.severity = suggestion + +# IDE0301: Use collection expression for empty +dotnet_diagnostic.IDE0301.severity = suggestion + +# IDE0305: Use collection expression for fluent +dotnet_diagnostic.IDE0305.severity = suggestion + +# IDE1005: Use conditional delegate call +dotnet_diagnostic.IDE1005.severity = suggestion + +# CA1859: Use concrete types when possible for improved performance +dotnet_diagnostic.CA1859.severity = suggestion + +# CA2202: Avoid inexact read with Stream.Read +dotnet_diagnostic.CA2022.severity = suggestion + +# CA2263: Prefer generic overload when type is known +dotnet_diagnostic.CA2263.severity = suggestion diff --git a/src/Common.Dotnet.AotCompatibility.props b/src/Common.Dotnet.AotCompatibility.props new file mode 100644 index 000000000000..9c9b3faa250d --- /dev/null +++ b/src/Common.Dotnet.AotCompatibility.props @@ -0,0 +1,9 @@ + + + + + true + true + 2 + + diff --git a/src/Monaco.props b/src/Monaco.props index 0aeef121e25a..471772823dd7 100644 --- a/src/Monaco.props +++ b/src/Monaco.props @@ -2,8 +2,8 @@ - - Assets\Monaco\customTokenColors.js + + Assets\Monaco\customTokenThemeRules.js Always diff --git a/src/Monaco/customLanguages/gitignore.js b/src/Monaco/customLanguages/gitignore.js index e4539dd50a12..8b5d39399345 100644 --- a/src/Monaco/customLanguages/gitignore.js +++ b/src/Monaco/customLanguages/gitignore.js @@ -6,7 +6,7 @@ root: [ [/^#.*$/, 'comment'], [/.*((? \d{2}:\d{2}:\d{2},\d{3}/, { + cases: { + '@eos': {token: 'type.identifier', next: '@subtitle'}, + '@default': {token: 'type.identifier', next: '@ignore'} + } + }], + [/^$/, 'string', '@pop'] + ], + + ignore: [ + [/.+$/, '', '@subtitle'] + ], + + subtitle: [ + [/^$/, 'string', '@popall'], + [/<\/?(?:[ibu]|font(?:\s+color="[^"]+"\s*)?)>/, 'tag'], + [/./, 'string'] + ] + } + }; +} \ No newline at end of file diff --git a/src/Monaco/customTokenColors.js b/src/Monaco/customTokenColors.js deleted file mode 100644 index aa20d58d42d0..000000000000 --- a/src/Monaco/customTokenColors.js +++ /dev/null @@ -1,3 +0,0 @@ -export const customTokenColors = [ - {token: 'custom-gitignore.negation', foreground: 'c00ce0'} -]; \ No newline at end of file diff --git a/src/Monaco/customTokenThemeRules.js b/src/Monaco/customTokenThemeRules.js new file mode 100644 index 000000000000..cbba1b1f3938 --- /dev/null +++ b/src/Monaco/customTokenThemeRules.js @@ -0,0 +1,3 @@ +export const customTokenThemeRules = [ + {token: 'custom-negation.gitignore', foreground: 'c00ce0'} +]; \ No newline at end of file diff --git a/src/Monaco/index.html b/src/Monaco/index.html index 1888cdac3960..54f7524225bf 100644 --- a/src/Monaco/index.html +++ b/src/Monaco/index.html @@ -9,17 +9,19 @@ // `theme` can be "vs" for light theme or "vs-dark" for dark theme // `lang` is the language of the file // `wrap` if the editor is wrapping or not + // `minimap` if the minimap is shown + // `contextMenu` whether to use the Monaco context menu. The built-in context menu + // doesn't work in Peek, so we set this to false and create a custom one var theme = ("[[PT_THEME]]" == "dark") ? "vs-dark" : "vs"; + var wrap = [[PT_WRAP]]; + var minimap = [[PT_MINIMAP]]; + var stickyScroll = [[PT_STICKY_SCROLL]]; + var fontSize = [[PT_FONT_SIZE]]; + var lang = "[[PT_LANG]]"; - var wrap = ([[PT_WRAP]] == 1) ? true : false; - var base64code = "[[PT_CODE]]"; - - var stickyScroll = ([[PT_STICKY_SCROLL]] == 1) ? true : false; - - var fontSize = [[PT_FONT_SIZE]]; - var contextMenu = ([[PT_CONTEXTMENU]] == 1) ? true : false; + var contextMenu = [[PT_CONTEXTMENU]]; var editor; @@ -29,12 +31,13 @@ }).join('')); function runToggleTextWrapCommand() { - if (wrap) { - editor.updateOptions({ wordWrap: 'off' }) - } else { - editor.updateOptions({ wordWrap: 'on' }) - } wrap = !wrap; + editor.updateOptions({ wordWrap: wrap ? 'on' : 'off' }); + } + + function runToggleMinimap() { + minimap = !minimap; + editor.updateOptions({minimap: {enabled: minimap}}); } function runCopyCommand() { @@ -79,7 +82,7 @@ - + \ No newline at end of file diff --git a/src/Monaco/monacoSpecialLanguages.js b/src/Monaco/monacoSpecialLanguages.js index c213f617bb76..5a76713a66cd 100644 --- a/src/Monaco/monacoSpecialLanguages.js +++ b/src/Monaco/monacoSpecialLanguages.js @@ -2,18 +2,20 @@ import { regDefinition } from './customLanguages/reg.js'; import { gitignoreDefinition } from './customLanguages/gitignore.js'; +import { srtDefinition } from './customLanguages/srt.js'; export async function registerAdditionalLanguages(monaco){ await languageDefinitions(); - registerAdditionalLanguage("cppExt", [".ino", ".pde"], "cpp", monaco) - registerAdditionalLanguage("xmlExt", [".wsdl", ".csproj", ".vcxproj", ".vbproj", ".fsproj"], "xml", monaco) - registerAdditionalLanguage("txtExt", [".sln", ".log", ".vsconfig", ".env", ".srt"], "txt", monaco) - registerAdditionalLanguage("razorExt", [".razor"], "razor", monaco) - registerAdditionalLanguage("vbExt", [".vbs"], "vb", monaco) - registerAdditionalLanguage("iniExt", [".inf", ".gitconfig", ".gitattributes", ".editorconfig"], "ini", monaco) - registerAdditionalLanguage("shellExt", [".ksh", ".zsh", ".bsh"], "shell", monaco) - registerAdditionalNewLanguage("reg", [".reg"], regDefinition(), monaco) - registerAdditionalNewLanguage("gitignore", [".gitignore"], gitignoreDefinition(), monaco) + registerAdditionalLanguage("cppExt", [".ino", ".pde"], "cpp", monaco); + registerAdditionalLanguage("xmlExt", [".wsdl", ".csproj", ".vcxproj", ".vbproj", ".fsproj", ".resx", ".resw"], "xml", monaco); + registerAdditionalLanguage("txtExt", [".sln", ".log", ".vsconfig", ".env", ".ahk", ".ion"], "txt", monaco); + registerAdditionalLanguage("razorExt", [".razor"], "razor", monaco); + registerAdditionalLanguage("vbExt", [".vbs"], "vb", monaco); + registerAdditionalLanguage("iniExt", [".inf", ".gitconfig", ".gitattributes", ".editorconfig"], "ini", monaco); + registerAdditionalLanguage("shellExt", [".ksh", ".zsh", ".bsh"], "shell", monaco); + registerAdditionalNewLanguage("reg", [".reg"], regDefinition(), monaco); + registerAdditionalNewLanguage("gitignore", [".gitignore"], gitignoreDefinition(), monaco); + registerAdditionalNewLanguage("srt", [".srt"], srtDefinition(), monaco); } // Language definitions taken from Monaco source code diff --git a/src/Monaco/monaco_languages.json b/src/Monaco/monaco_languages.json index 28fa3c98b448..8f0408dc9b54 100644 --- a/src/Monaco/monaco_languages.json +++ b/src/Monaco/monaco_languages.json @@ -1 +1 @@ -{"list":[{"id":"plaintext","extensions":[".txt"],"aliases":["Plain Text","text"],"mimetypes":["text/plain"]},{"id":"abap","extensions":[".abap"],"aliases":["abap","ABAP"]},{"id":"apex","extensions":[".cls"],"aliases":["Apex","apex"],"mimetypes":["text/x-apex-source","text/x-apex"]},{"id":"azcli","extensions":[".azcli"],"aliases":["Azure CLI","azcli"]},{"id":"bat","extensions":[".bat",".cmd"],"aliases":["Batch","bat"]},{"id":"bicep","extensions":[".bicep"],"aliases":["Bicep"]},{"id":"cameligo","extensions":[".mligo"],"aliases":["Cameligo"]},{"id":"clojure","extensions":[".clj",".cljs",".cljc",".edn"],"aliases":["clojure","Clojure"]},{"id":"coffeescript","extensions":[".coffee"],"aliases":["CoffeeScript","coffeescript","coffee"],"mimetypes":["text/x-coffeescript","text/coffeescript"]},{"id":"c","extensions":[".c",".h"],"aliases":["C","c"]},{"id":"cpp","extensions":[".cpp",".cc",".cxx",".hpp",".hh",".hxx"],"aliases":["C++","Cpp","cpp"]},{"id":"csharp","extensions":[".cs",".csx",".cake"],"aliases":["C#","csharp"]},{"id":"csp","extensions":[],"aliases":["CSP","csp"]},{"id":"css","extensions":[".css"],"aliases":["CSS","css"],"mimetypes":["text/css"]},{"id":"cypher","extensions":[".cypher",".cyp"],"aliases":["Cypher","OpenCypher"]},{"id":"dart","extensions":[".dart"],"aliases":["Dart","dart"],"mimetypes":["text/x-dart-source","text/x-dart"]},{"id":"dockerfile","extensions":[".dockerfile"],"filenames":["Dockerfile"],"aliases":["Dockerfile"]},{"id":"ecl","extensions":[".ecl"],"aliases":["ECL","Ecl","ecl"]},{"id":"elixir","extensions":[".ex",".exs"],"aliases":["Elixir","elixir","ex"]},{"id":"flow9","extensions":[".flow"],"aliases":["Flow9","Flow","flow9","flow"]},{"id":"fsharp","extensions":[".fs",".fsi",".ml",".mli",".fsx",".fsscript"],"aliases":["F#","FSharp","fsharp"]},{"id":"freemarker2","extensions":[".ftl",".ftlh",".ftlx"],"aliases":["FreeMarker2","Apache FreeMarker2"]},{"id":"freemarker2.tag-angle.interpolation-dollar","aliases":["FreeMarker2 (Angle/Dollar)","Apache FreeMarker2 (Angle/Dollar)"]},{"id":"freemarker2.tag-bracket.interpolation-dollar","aliases":["FreeMarker2 (Bracket/Dollar)","Apache FreeMarker2 (Bracket/Dollar)"]},{"id":"freemarker2.tag-angle.interpolation-bracket","aliases":["FreeMarker2 (Angle/Bracket)","Apache FreeMarker2 (Angle/Bracket)"]},{"id":"freemarker2.tag-bracket.interpolation-bracket","aliases":["FreeMarker2 (Bracket/Bracket)","Apache FreeMarker2 (Bracket/Bracket)"]},{"id":"freemarker2.tag-auto.interpolation-dollar","aliases":["FreeMarker2 (Auto/Dollar)","Apache FreeMarker2 (Auto/Dollar)"]},{"id":"freemarker2.tag-auto.interpolation-bracket","aliases":["FreeMarker2 (Auto/Bracket)","Apache FreeMarker2 (Auto/Bracket)"]},{"id":"go","extensions":[".go"],"aliases":["Go"]},{"id":"graphql","extensions":[".graphql",".gql"],"aliases":["GraphQL","graphql","gql"],"mimetypes":["application/graphql"]},{"id":"handlebars","extensions":[".handlebars",".hbs"],"aliases":["Handlebars","handlebars","hbs"],"mimetypes":["text/x-handlebars-template"]},{"id":"hcl","extensions":[".tf",".tfvars",".hcl"],"aliases":["Terraform","tf","HCL","hcl"]},{"id":"html","extensions":[".html",".htm",".shtml",".xhtml",".mdoc",".jsp",".asp",".aspx",".jshtm"],"aliases":["HTML","htm","html","xhtml"],"mimetypes":["text/html","text/x-jshtm","text/template","text/ng-template"]},{"id":"ini","extensions":[".ini",".properties",".gitconfig"],"filenames":["config",".gitattributes",".gitconfig",".editorconfig"],"aliases":["Ini","ini"]},{"id":"java","extensions":[".java",".jav"],"aliases":["Java","java"],"mimetypes":["text/x-java-source","text/x-java"]},{"id":"javascript","extensions":[".js",".es6",".jsx",".mjs",".cjs"],"firstLine":"^#!.*\\bnode","filenames":["jakefile"],"aliases":["JavaScript","javascript","js"],"mimetypes":["text/javascript"]},{"id":"julia","extensions":[".jl"],"aliases":["julia","Julia"]},{"id":"kotlin","extensions":[".kt",".kts"],"aliases":["Kotlin","kotlin"],"mimetypes":["text/x-kotlin-source","text/x-kotlin"]},{"id":"less","extensions":[".less"],"aliases":["Less","less"],"mimetypes":["text/x-less","text/less"]},{"id":"lexon","extensions":[".lex"],"aliases":["Lexon"]},{"id":"lua","extensions":[".lua"],"aliases":["Lua","lua"]},{"id":"liquid","extensions":[".liquid",".html.liquid"],"aliases":["Liquid","liquid"],"mimetypes":["application/liquid"]},{"id":"m3","extensions":[".m3",".i3",".mg",".ig"],"aliases":["Modula-3","Modula3","modula3","m3"]},{"id":"markdown","extensions":[".md",".markdown",".mdown",".mkdn",".mkd",".mdwn",".mdtxt",".mdtext"],"aliases":["Markdown","markdown"]},{"id":"mdx","extensions":[".mdx"],"aliases":["MDX","mdx"]},{"id":"mips","extensions":[".s"],"aliases":["MIPS","MIPS-V"],"mimetypes":["text/x-mips","text/mips","text/plaintext"]},{"id":"msdax","extensions":[".dax",".msdax"],"aliases":["DAX","MSDAX"]},{"id":"mysql","extensions":[],"aliases":["MySQL","mysql"]},{"id":"objective-c","extensions":[".m"],"aliases":["Objective-C"]},{"id":"pascal","extensions":[".pas",".p",".pp"],"aliases":["Pascal","pas"],"mimetypes":["text/x-pascal-source","text/x-pascal"]},{"id":"pascaligo","extensions":[".ligo"],"aliases":["Pascaligo","ligo"]},{"id":"perl","extensions":[".pl",".pm"],"aliases":["Perl","pl"]},{"id":"pgsql","extensions":[],"aliases":["PostgreSQL","postgres","pg","postgre"]},{"id":"php","extensions":[".php",".php4",".php5",".phtml",".ctp"],"aliases":["PHP","php"],"mimetypes":["application/x-php"]},{"id":"pla","extensions":[".pla"]},{"id":"postiats","extensions":[".dats",".sats",".hats"],"aliases":["ATS","ATS/Postiats"]},{"id":"powerquery","extensions":[".pq",".pqm"],"aliases":["PQ","M","Power Query","Power Query M"]},{"id":"powershell","extensions":[".ps1",".psm1",".psd1"],"aliases":["PowerShell","powershell","ps","ps1"]},{"id":"proto","extensions":[".proto"],"aliases":["protobuf","Protocol Buffers"]},{"id":"pug","extensions":[".jade",".pug"],"aliases":["Pug","Jade","jade"]},{"id":"python","extensions":[".py",".rpy",".pyw",".cpy",".gyp",".gypi"],"aliases":["Python","py"],"firstLine":"^#!/.*\\bpython[0-9.-]*\\b"},{"id":"qsharp","extensions":[".qs"],"aliases":["Q#","qsharp"]},{"id":"r","extensions":[".r",".rhistory",".rmd",".rprofile",".rt"],"aliases":["R","r"]},{"id":"razor","extensions":[".cshtml"],"aliases":["Razor","razor"],"mimetypes":["text/x-cshtml"]},{"id":"redis","extensions":[".redis"],"aliases":["redis"]},{"id":"redshift","extensions":[],"aliases":["Redshift","redshift"]},{"id":"restructuredtext","extensions":[".rst"],"aliases":["reStructuredText","restructuredtext"]},{"id":"ruby","extensions":[".rb",".rbx",".rjs",".gemspec",".pp"],"filenames":["rakefile","Gemfile"],"aliases":["Ruby","rb"]},{"id":"rust","extensions":[".rs",".rlib"],"aliases":["Rust","rust"]},{"id":"sb","extensions":[".sb"],"aliases":["Small Basic","sb"]},{"id":"scala","extensions":[".scala",".sc",".sbt"],"aliases":["Scala","scala","SBT","Sbt","sbt","Dotty","dotty"],"mimetypes":["text/x-scala-source","text/x-scala","text/x-sbt","text/x-dotty"]},{"id":"scheme","extensions":[".scm",".ss",".sch",".rkt"],"aliases":["scheme","Scheme"]},{"id":"scss","extensions":[".scss"],"aliases":["Sass","sass","scss"],"mimetypes":["text/x-scss","text/scss"]},{"id":"shell","extensions":[".sh",".bash"],"aliases":["Shell","sh"]},{"id":"sol","extensions":[".sol"],"aliases":["sol","solidity","Solidity"]},{"id":"aes","extensions":[".aes"],"aliases":["aes","sophia","Sophia"]},{"id":"sparql","extensions":[".rq"],"aliases":["sparql","SPARQL"]},{"id":"sql","extensions":[".sql"],"aliases":["SQL"]},{"id":"st","extensions":[".st",".iecst",".iecplc",".lc3lib",".TcPOU",".TcDUT",".TcGVL",".TcIO"],"aliases":["StructuredText","scl","stl"]},{"id":"swift","aliases":["Swift","swift"],"extensions":[".swift"],"mimetypes":["text/swift"]},{"id":"systemverilog","extensions":[".sv",".svh"],"aliases":["SV","sv","SystemVerilog","systemverilog"]},{"id":"verilog","extensions":[".v",".vh"],"aliases":["V","v","Verilog","verilog"]},{"id":"tcl","extensions":[".tcl"],"aliases":["tcl","Tcl","tcltk","TclTk","tcl/tk","Tcl/Tk"]},{"id":"twig","extensions":[".twig"],"aliases":["Twig","twig"],"mimetypes":["text/x-twig"]},{"id":"typescript","extensions":[".ts",".tsx",".cts",".mts"],"aliases":["TypeScript","ts","typescript"],"mimetypes":["text/typescript"]},{"id":"vb","extensions":[".vb"],"aliases":["Visual Basic","vb"]},{"id":"wgsl","extensions":[".wgsl"],"aliases":["WebGPU Shading Language","WGSL","wgsl"]},{"id":"xml","extensions":[".xml",".xsd",".dtd",".ascx",".csproj",".config",".props",".targets",".wxi",".wxl",".wxs",".xaml",".svg",".svgz",".opf",".xslt",".xsl"],"firstLine":"(\\<\\?xml.*)|(\\(std::round(rect.left * static_cast(DEFAULT_DPI) / dpi_x)); + rect.right = static_cast(std::round(rect.right * static_cast(DEFAULT_DPI) / dpi_x)); + rect.top = static_cast(std::round(rect.top * static_cast(DEFAULT_DPI) / dpi_y)); + rect.bottom = static_cast(std::round(rect.bottom * static_cast(DEFAULT_DPI) / dpi_y)); + } + } + void EnableDPIAwarenessForThisProcess() { SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); diff --git a/src/common/Display/dpi_aware.h b/src/common/Display/dpi_aware.h index a63365aa2fb7..bbbb61fd4046 100644 --- a/src/common/Display/dpi_aware.h +++ b/src/common/Display/dpi_aware.h @@ -15,6 +15,7 @@ namespace DPIAware void Convert(HMONITOR monitor_handle, RECT& rect); void ConvertByCursorPosition(float& width, float& height); void InverseConvert(HMONITOR monitor_handle, float& width, float& height); + void InverseConvert(HMONITOR monitor_handle, RECT& rect); void EnableDPIAwarenessForThisProcess(); enum AwarenessLevel diff --git a/src/common/Display/monitors.cpp b/src/common/Display/monitors.cpp index c203d15712d6..2c9a22e42560 100644 --- a/src/common/Display/monitors.cpp +++ b/src/common/Display/monitors.cpp @@ -52,3 +52,55 @@ MonitorInfo MonitorInfo::GetPrimaryMonitor() } return monitors[0]; } + +MonitorInfo MonitorInfo::GetFromWindow(const HWND window) +{ + auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); + return MonitorInfo::MonitorInfo(monitor); +} + +MonitorInfo MonitorInfo::GetFromPoint(int32_t x, int32_t y) +{ + auto monitor = MonitorFromPoint(POINT{ x, y }, MONITOR_DEFAULTTONULL); + return MonitorInfo::MonitorInfo(monitor); +} + +MonitorInfo::Size MonitorInfo::GetSize(const MONITORINFOEX& monitorInfoEx) +{ + Size size = {}; + + auto device_name = PCTSTR(monitorInfoEx.szDevice); + + auto hdc = CreateDC(device_name, nullptr, nullptr, nullptr); + size.width_mm = static_cast(GetDeviceCaps(hdc, HORZSIZE)); + size.height_mm = static_cast(GetDeviceCaps(hdc, VERTSIZE)); + if (hdc != nullptr) + { + ReleaseDC(nullptr, hdc); + } + + auto monitor = &monitorInfoEx.rcMonitor; + size.width_logical = static_cast(monitor->right - monitor->left); + size.height_logical = static_cast(monitor->bottom - monitor->top); + + DEVMODE dev_mode = { .dmSize = sizeof DEVMODE }; + if (EnumDisplaySettingsEx(device_name, ENUM_CURRENT_SETTINGS, &dev_mode, EDS_RAWMODE)) + { + size.width_physical = dev_mode.dmPelsWidth; + size.height_physical = dev_mode.dmPelsHeight; + } + + return size; +} + +MonitorInfo::Size MonitorInfo::GetSize() const +{ + if (this->handle) + { + return MonitorInfo::GetSize(this->info); + } + else + { + return MonitorInfo::Size{}; + } +} diff --git a/src/common/Display/monitors.h b/src/common/Display/monitors.h index 021f2b9efb8b..614a2258ddcf 100644 --- a/src/common/Display/monitors.h +++ b/src/common/Display/monitors.h @@ -1,4 +1,5 @@ #pragma once +#pragma comment(lib, "Gdi32.lib") #include #include @@ -42,6 +43,15 @@ struct Box class MonitorInfo { +public: + typedef struct Size + { + uint32_t width_logical, height_logical; + uint32_t width_physical, height_physical; + float width_mm, height_mm; + } Size; + +private: HMONITOR handle; MONITORINFOEX info = {}; @@ -53,8 +63,14 @@ class MonitorInfo } Box GetScreenSize(const bool includeNonWorkingArea) const; bool IsPrimary() const; + Size GetSize() const; // Returns monitor rects ordered from left to right static std::vector GetMonitors(bool includeNonWorkingArea); static MonitorInfo GetPrimaryMonitor(); + static MonitorInfo GetFromWindow(HWND); + static MonitorInfo GetFromPoint(int32_t, int32_t); + +private: + static Size GetSize(const MONITORINFOEX&); }; diff --git a/src/common/FilePreviewCommon/FilePreviewCommon.csproj b/src/common/FilePreviewCommon/FilePreviewCommon.csproj index 28865605a06d..560fbf328704 100644 --- a/src/common/FilePreviewCommon/FilePreviewCommon.csproj +++ b/src/common/FilePreviewCommon/FilePreviewCommon.csproj @@ -2,6 +2,7 @@ + PowerToys FilePreviewCommon diff --git a/src/common/FilePreviewCommon/Formatters/FilePreviewJsonSerializerContext.cs b/src/common/FilePreviewCommon/Formatters/FilePreviewJsonSerializerContext.cs new file mode 100644 index 000000000000..d9f72eefc727 --- /dev/null +++ b/src/common/FilePreviewCommon/Formatters/FilePreviewJsonSerializerContext.cs @@ -0,0 +1,13 @@ +// 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.Text.Json; +using System.Text.Json.Serialization; + +namespace Microsoft.PowerToys.FilePreviewCommon.Monaco.Formatters; + +[JsonSerializable(typeof(JsonDocument))] +internal sealed partial class FilePreviewJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/src/common/FilePreviewCommon/Formatters/JsonFormatter.cs b/src/common/FilePreviewCommon/Formatters/JsonFormatter.cs index 91b7013c6fdd..bc30ec23d568 100644 --- a/src/common/FilePreviewCommon/Formatters/JsonFormatter.cs +++ b/src/common/FilePreviewCommon/Formatters/JsonFormatter.cs @@ -18,6 +18,8 @@ public class JsonFormatter : IFormatter Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, }; + private static readonly FilePreviewJsonSerializerContext _filePreviewJsonSerializerContext = new(_serializerOptions); + /// public string Format(string value) { @@ -28,7 +30,7 @@ public string Format(string value) using (var jDocument = JsonDocument.Parse(value, new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip })) { - return JsonSerializer.Serialize(jDocument, _serializerOptions); + return JsonSerializer.Serialize(jDocument, _filePreviewJsonSerializerContext.JsonDocument); } } } diff --git a/src/common/FilePreviewCommon/MonacoHelper.cs b/src/common/FilePreviewCommon/MonacoHelper.cs index 20ea747e2ecc..3aff51fe6ec0 100644 --- a/src/common/FilePreviewCommon/MonacoHelper.cs +++ b/src/common/FilePreviewCommon/MonacoHelper.cs @@ -6,9 +6,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Reflection; using System.Text.Json; - using Microsoft.PowerToys.FilePreviewCommon.Monaco.Formatters; namespace Microsoft.PowerToys.FilePreviewCommon @@ -29,34 +27,32 @@ public static class MonacoHelper new XmlFormatter(), }.AsReadOnly(); - private static string? _monacoDirectory; + private static readonly Lazy _monacoDirectory = new(GetRuntimeMonacoDirectory); + + /// + /// Gets the path of the Monaco assets folder. + /// + public static string MonacoDirectory => _monacoDirectory.Value; - public static string GetRuntimeMonacoDirectory() + private static string GetRuntimeMonacoDirectory() { - string codeBase = Assembly.GetExecutingAssembly().Location; - string path = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(codeBase) ?? string.Empty, "Assets", "Monaco")); - if (Path.Exists(path)) - { - return path; - } - else + string baseDirectory = AppContext.BaseDirectory ?? string.Empty; + + // AppContext.BaseDirectory returns a stray \\ so we want to remove that. + baseDirectory = Path.TrimEndingDirectorySeparator(baseDirectory); + + // If the executable is within "WinUI3Apps", correct the path first. + // The idea of GetFileName here is getting the last directory in the path. + if (Path.GetFileName(baseDirectory) == "WinUI3Apps") { - // We're likely in WinUI3Apps directory and need to go back to the base directory. - return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(codeBase) ?? string.Empty, "..", "Assets", "Monaco")); + baseDirectory = Path.Combine(baseDirectory, ".."); } - } - public static string MonacoDirectory - { - get - { - if (string.IsNullOrEmpty(_monacoDirectory)) - { - _monacoDirectory = GetRuntimeMonacoDirectory(); - } + string monacoPath = Path.Combine(baseDirectory, "Assets", "Monaco"); - return _monacoDirectory; - } + return Directory.Exists(monacoPath) ? + monacoPath : + throw new DirectoryNotFoundException($"Monaco assets directory not found at {monacoPath}"); } public static JsonDocument GetLanguages() diff --git a/src/common/GPOWrapper/GPOWrapper.cpp b/src/common/GPOWrapper/GPOWrapper.cpp index a9ecb43818e6..02075707b7e4 100644 --- a/src/common/GPOWrapper/GPOWrapper.cpp +++ b/src/common/GPOWrapper/GPOWrapper.cpp @@ -128,9 +128,9 @@ namespace winrt::PowerToys::GPOWrapper::implementation { return static_cast(powertoys_gpo::getConfiguredAdvancedPasteEnabledValue()); } - GpoRuleConfigured GPOWrapper::GetConfiguredVideoConferenceMuteEnabledValue() + GpoRuleConfigured GPOWrapper::GetConfiguredZoomItEnabledValue() { - return static_cast(powertoys_gpo::getConfiguredVideoConferenceMuteEnabledValue()); + return static_cast(powertoys_gpo::getConfiguredZoomItEnabledValue()); } GpoRuleConfigured GPOWrapper::GetConfiguredMouseWithoutBordersEnabledValue() { diff --git a/src/common/GPOWrapper/GPOWrapper.h b/src/common/GPOWrapper/GPOWrapper.h index 34c1e3646be2..71f9799c857b 100644 --- a/src/common/GPOWrapper/GPOWrapper.h +++ b/src/common/GPOWrapper/GPOWrapper.h @@ -39,7 +39,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation static GpoRuleConfigured GetConfiguredShortcutGuideEnabledValue(); static GpoRuleConfigured GetConfiguredTextExtractorEnabledValue(); static GpoRuleConfigured GetConfiguredAdvancedPasteEnabledValue(); - static GpoRuleConfigured GetConfiguredVideoConferenceMuteEnabledValue(); + static GpoRuleConfigured GetConfiguredZoomItEnabledValue(); static GpoRuleConfigured GetConfiguredPeekEnabledValue(); static GpoRuleConfigured GetDisableNewUpdateToastValue(); static GpoRuleConfigured GetDisableAutomaticUpdateDownloadValue(); diff --git a/src/common/GPOWrapper/GPOWrapper.idl b/src/common/GPOWrapper/GPOWrapper.idl index af58834a0c13..256a77a7399f 100644 --- a/src/common/GPOWrapper/GPOWrapper.idl +++ b/src/common/GPOWrapper/GPOWrapper.idl @@ -43,7 +43,7 @@ namespace PowerToys static GpoRuleConfigured GetConfiguredShortcutGuideEnabledValue(); static GpoRuleConfigured GetConfiguredTextExtractorEnabledValue(); static GpoRuleConfigured GetConfiguredAdvancedPasteEnabledValue(); - static GpoRuleConfigured GetConfiguredVideoConferenceMuteEnabledValue(); + static GpoRuleConfigured GetConfiguredZoomItEnabledValue(); static GpoRuleConfigured GetConfiguredPeekEnabledValue(); static GpoRuleConfigured GetDisableNewUpdateToastValue(); static GpoRuleConfigured GetDisableAutomaticUpdateDownloadValue(); diff --git a/src/common/GPOWrapper/pch.h b/src/common/GPOWrapper/pch.h index 21199686d54d..b10d0155ca8a 100644 --- a/src/common/GPOWrapper/pch.h +++ b/src/common/GPOWrapper/pch.h @@ -1,4 +1,4 @@ #pragma once -#include +#include #include #include diff --git a/src/common/ManagedCommon/Logger.cs b/src/common/ManagedCommon/Logger.cs index 367480d293a2..78b27afefcfc 100644 --- a/src/common/ManagedCommon/Logger.cs +++ b/src/common/ManagedCommon/Logger.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; using PowerToys.Interop; @@ -52,16 +53,18 @@ public static void InitializeLogger(string applicationLogPath, bool isLocalLow = Trace.AutoFlush = true; } + [MethodImpl(MethodImplOptions.NoInlining)] public static void LogError(string message) { Log(message, Error); } + [MethodImpl(MethodImplOptions.NoInlining)] public static void LogError(string message, Exception ex) { if (ex == null) { - LogError(message); + Log(message, Error); } else { @@ -84,26 +87,31 @@ public static void LogError(string message, Exception ex) } } + [MethodImpl(MethodImplOptions.NoInlining)] public static void LogWarning(string message) { Log(message, Warning); } + [MethodImpl(MethodImplOptions.NoInlining)] public static void LogInfo(string message) { Log(message, Info); } + [MethodImpl(MethodImplOptions.NoInlining)] public static void LogDebug(string message) { Log(message, Debug); } + [MethodImpl(MethodImplOptions.NoInlining)] public static void LogTrace() { Log(string.Empty, TraceFlag); } + [MethodImpl(MethodImplOptions.NoInlining)] private static void Log(string message, string type) { Trace.WriteLine("[" + DateTime.Now.TimeOfDay + "] [" + type + "] " + GetCallerInfo()); @@ -116,13 +124,49 @@ private static void Log(string message, string type) Trace.Unindent(); } + [MethodImpl(MethodImplOptions.NoInlining)] private static string GetCallerInfo() { StackTrace stackTrace = new(); - var methodName = stackTrace.GetFrame(3)?.GetMethod(); - var className = methodName?.DeclaringType.Name; - return className + "::" + methodName?.Name; + var callerMethod = GetCallerMethod(stackTrace); + + return $"{callerMethod?.DeclaringType?.Name}::{callerMethod.Name}"; + } + + private static MethodBase GetCallerMethod(StackTrace stackTrace) + { + const int topFrame = 3; + + var topMethod = stackTrace.GetFrame(topFrame)?.GetMethod(); + + try + { + if (topMethod?.Name == nameof(IAsyncStateMachine.MoveNext) && typeof(IAsyncStateMachine).IsAssignableFrom(topMethod?.DeclaringType)) + { + // Async method; return actual method as determined by heuristic: + // "Nearest method on stack to async state-machine's MoveNext() in same namespace but in a different type". + // There are tighter ways of determining the actual method, but this is good enough and probably faster. + for (int deepFrame = topFrame + 1; deepFrame < stackTrace.FrameCount; deepFrame++) + { + var deepMethod = stackTrace.GetFrame(deepFrame)?.GetMethod(); + + if (deepMethod?.DeclaringType != topMethod?.DeclaringType && deepMethod?.DeclaringType?.Namespace == topMethod?.DeclaringType?.Namespace) + { + return deepMethod; + } + } + } + } + catch (Exception) + { + // Ignore exceptions in Release. The code above won't throw, but if it does, we don't want to crash the app. +#if DEBUG + throw; +#endif + } + + return topMethod; } } } diff --git a/src/common/ManagedCommon/ModuleType.cs b/src/common/ManagedCommon/ModuleType.cs index 7a1913c05c73..5b95af43d83b 100644 --- a/src/common/ManagedCommon/ModuleType.cs +++ b/src/common/ManagedCommon/ModuleType.cs @@ -32,5 +32,6 @@ public enum ModuleType ShortcutGuide, PowerOCR, Workspaces, + ZoomIt, } } diff --git a/src/common/ManagedCommon/NativeMethods.cs b/src/common/ManagedCommon/NativeMethods.cs index feffafa94637..998010f10a29 100644 --- a/src/common/ManagedCommon/NativeMethods.cs +++ b/src/common/ManagedCommon/NativeMethods.cs @@ -42,6 +42,9 @@ internal static class NativeMethods [DllImport("user32.dll")] internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); + [DllImport("dwmapi")] + internal static extern IntPtr DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset); + [StructLayout(LayoutKind.Sequential)] public struct INPUT { @@ -100,5 +103,14 @@ internal enum INPUTTYPE : uint INPUT_KEYBOARD = 1, INPUT_HARDWARE = 2, } + + [StructLayout(LayoutKind.Sequential)] + internal struct MARGINS + { + public int cxLeftWidth; + public int cxRightWidth; + public int cyTopHeight; + public int cyBottomHeight; + } } } diff --git a/src/common/Common.UI/OSVersionHelper.cs b/src/common/ManagedCommon/OSVersionHelper.cs similarity index 75% rename from src/common/Common.UI/OSVersionHelper.cs rename to src/common/ManagedCommon/OSVersionHelper.cs index aa2a2a953a4f..6a865b7ae18e 100644 --- a/src/common/Common.UI/OSVersionHelper.cs +++ b/src/common/ManagedCommon/OSVersionHelper.cs @@ -4,10 +4,15 @@ using System; -namespace Common.UI +namespace ManagedCommon { public static class OSVersionHelper { + public static bool IsWindows10() + { + return Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Minor < 22000; + } + public static bool IsWindows11() { return Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Build >= 22000; diff --git a/src/common/ManagedCommon/WindowHelpers.cs b/src/common/ManagedCommon/WindowHelpers.cs index bd9d3347229b..c5ee13f69cfd 100644 --- a/src/common/ManagedCommon/WindowHelpers.cs +++ b/src/common/ManagedCommon/WindowHelpers.cs @@ -35,5 +35,20 @@ public static void BringToForeground(IntPtr handle) } } } + + /// + /// Workaround for a WinUI bug on Windows 10 in which a window's top border is always + /// black. Calls DwmExtendFrameIntoClientArea() with a cyTopHeight of 2 to force + /// the window's top border to be visible.

+ /// Is a no-op on versions other than Windows 10. + ///
+ public static void ForceTopBorder1PixelInsetOnWindows10(IntPtr handle) + { + if (OSVersionHelper.IsWindows10()) + { + var margins = new NativeMethods.MARGINS { cxLeftWidth = 0, cxRightWidth = 0, cyBottomHeight = 0, cyTopHeight = 2 }; + NativeMethods.DwmExtendFrameIntoClientArea(handle, ref margins); + } + } } } diff --git a/src/common/SettingsAPI/settings_objects.cpp b/src/common/SettingsAPI/settings_objects.cpp index 6f3aa4c792dc..f9a72cee6244 100644 --- a/src/common/SettingsAPI/settings_objects.cpp +++ b/src/common/SettingsAPI/settings_objects.cpp @@ -331,6 +331,15 @@ namespace PowerToysSettings return static_cast(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value")); } + std::optional PowerToyValues::get_uint_value(std::wstring_view property_name) const + { + if (!has_property(m_json, property_name, json::JsonValueType::Number)) + { + return std::nullopt; + } + return static_cast(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value")); + } + std::optional PowerToyValues::get_string_value(std::wstring_view property_name) const { if (!has_property(m_json, property_name, json::JsonValueType::String)) diff --git a/src/common/SettingsAPI/settings_objects.h b/src/common/SettingsAPI/settings_objects.h index 1c84ac19b7d5..84b064d5af55 100644 --- a/src/common/SettingsAPI/settings_objects.h +++ b/src/common/SettingsAPI/settings_objects.h @@ -83,6 +83,7 @@ namespace PowerToysSettings std::optional get_bool_value(std::wstring_view property_name) const; std::optional get_int_value(std::wstring_view property_name) const; + std::optional get_uint_value(std::wstring_view property_name) const; std::optional get_string_value(std::wstring_view property_name) const; std::optional get_json(std::wstring_view property_name) const; json::JsonObject get_raw_json(); diff --git a/src/common/Telemetry/TelemetryBase.cs b/src/common/Telemetry/TelemetryBase.cs index d63ea2a5bef0..77733f22ae9a 100644 --- a/src/common/Telemetry/TelemetryBase.cs +++ b/src/common/Telemetry/TelemetryBase.cs @@ -39,7 +39,7 @@ public class TelemetryBase : EventSource public const EventKeywords ProjectKeywordMeasure = (EventKeywords)0x0; /// - /// Group ID for Powertoys project. + /// Group ID for PowerToys project. /// private static readonly string[] PowerToysTelemetryTraits = { "ETW_GROUP", "{42749043-438c-46a2-82be-c6cbeb192ff2}" }; diff --git a/src/common/interop/CommonManaged.cpp b/src/common/interop/CommonManaged.cpp index 39ae2967b42c..d59741fef6eb 100644 --- a/src/common/interop/CommonManaged.cpp +++ b/src/common/interop/CommonManaged.cpp @@ -2,8 +2,6 @@ #include "CommonManaged.h" #include "CommonManaged.g.cpp" #include -#include "../../modules/videoconference/VideoConferenceShared/MicrophoneDevice.h" -#include "../../modules/videoconference/VideoConferenceShared/VideoCaptureDeviceList.h" namespace winrt::PowerToys::Interop::implementation { @@ -11,29 +9,4 @@ namespace winrt::PowerToys::Interop::implementation { return hstring{ get_product_version() }; } - winrt::Windows::Foundation::Collections::IVector CommonManaged::GetAllActiveMicrophoneDeviceNames() - { - auto names = std::vector(); - for (const auto& device : MicrophoneDevice::getAllActive()) - { - names.push_back(device->name().data()); - } - return winrt::multi_threaded_vector(std::move(names)); - } - winrt::Windows::Foundation::Collections::IVector CommonManaged::GetAllVideoCaptureDeviceNames() - { - auto names = std::vector(); - VideoCaptureDeviceList vcdl; - vcdl.EnumerateDevices(); - - for (UINT32 i = 0; i < vcdl.Count(); ++i) - { - auto name = vcdl.GetDeviceName(i).data(); - if (name != L"PowerToys VideoConference Mute") - { - names.push_back(name); - } - } - return winrt::multi_threaded_vector(std::move(names)); - } } diff --git a/src/common/interop/CommonManaged.h b/src/common/interop/CommonManaged.h index 96d6f5d8a549..7196699ae996 100644 --- a/src/common/interop/CommonManaged.h +++ b/src/common/interop/CommonManaged.h @@ -8,8 +8,6 @@ namespace winrt::PowerToys::Interop::implementation CommonManaged() = default; static hstring GetProductVersion(); - static winrt::Windows::Foundation::Collections::IVector GetAllActiveMicrophoneDeviceNames(); - static winrt::Windows::Foundation::Collections::IVector GetAllVideoCaptureDeviceNames(); }; } namespace winrt::PowerToys::Interop::factory_implementation diff --git a/src/common/interop/CommonManaged.idl b/src/common/interop/CommonManaged.idl index 0a523e790a52..38e9225bb529 100644 --- a/src/common/interop/CommonManaged.idl +++ b/src/common/interop/CommonManaged.idl @@ -4,8 +4,6 @@ namespace PowerToys { [default_interface] static runtimeclass CommonManaged { static String GetProductVersion(); - static Windows.Foundation.Collections.IVector GetAllActiveMicrophoneDeviceNames(); - static Windows.Foundation.Collections.IVector GetAllVideoCaptureDeviceNames(); } } } \ No newline at end of file diff --git a/src/common/interop/PowerToys.Interop.vcxproj b/src/common/interop/PowerToys.Interop.vcxproj index 88115f9eabc5..aadd8b2ebb97 100644 --- a/src/common/interop/PowerToys.Interop.vcxproj +++ b/src/common/interop/PowerToys.Interop.vcxproj @@ -93,8 +93,6 @@ - - CommonManaged.idl @@ -123,8 +121,6 @@ - - CommonManaged.idl diff --git a/src/common/interop/PowerToys.Interop.vcxproj.filters b/src/common/interop/PowerToys.Interop.vcxproj.filters index 5df4afc36889..6fa51a327571 100644 --- a/src/common/interop/PowerToys.Interop.vcxproj.filters +++ b/src/common/interop/PowerToys.Interop.vcxproj.filters @@ -21,12 +21,6 @@ Header Files - - Header Files - - - Header Files - Header Files @@ -65,12 +59,6 @@ Source Files - - Source Files - - - Source Files - Source Files diff --git a/src/common/interop/keyboard_layout.cpp b/src/common/interop/keyboard_layout.cpp index 5254f1ee78e0..12253c55eb4a 100644 --- a/src/common/interop/keyboard_layout.cpp +++ b/src/common/interop/keyboard_layout.cpp @@ -241,10 +241,12 @@ void LayoutMap::LayoutMapImpl::UpdateLayout() keyboardLayoutMap[VK_KANA] = L"IME Kana"; keyboardLayoutMap[VK_HANGEUL] = L"IME Hangeul"; keyboardLayoutMap[VK_HANGUL] = L"IME Hangul"; + keyboardLayoutMap[VK_IME_ON] = L"IME On"; keyboardLayoutMap[VK_JUNJA] = L"IME Junja"; keyboardLayoutMap[VK_FINAL] = L"IME Final"; keyboardLayoutMap[VK_HANJA] = L"IME Hanja"; keyboardLayoutMap[VK_KANJI] = L"IME Kanji"; + keyboardLayoutMap[VK_IME_OFF] = L"IME Off"; keyboardLayoutMap[VK_CONVERT] = L"IME Convert"; keyboardLayoutMap[VK_NONCONVERT] = L"IME Non-Convert"; keyboardLayoutMap[VK_ACCEPT] = L"IME Kana"; diff --git a/src/common/interop/pch.h b/src/common/interop/pch.h index 0934324c057c..c4835a98e1ca 100644 --- a/src/common/interop/pch.h +++ b/src/common/interop/pch.h @@ -6,7 +6,7 @@ #pragma once #define WIN32_LEAN_AND_MEAN // add headers that you want to pre-compile here -#include +#include #include #include #include diff --git a/src/common/interop/shared_constants.h b/src/common/interop/shared_constants.h index d16f49d8f1a9..1c4808ad6a21 100644 --- a/src/common/interop/shared_constants.h +++ b/src/common/interop/shared_constants.h @@ -124,6 +124,10 @@ namespace CommonSharedConstants const wchar_t SHOW_ENVIRONMENT_VARIABLES_EVENT[] = L"Local\\PowerToysEnvironmentVariables-ShowEnvironmentVariablesEvent-1021f616-e951-4d64-b231-a8f972159978"; const wchar_t SHOW_ENVIRONMENT_VARIABLES_ADMIN_EVENT[] = L"Local\\PowerToysEnvironmentVariables-EnvironmentVariablesAdminEvent-8c95d2ad-047c-49a2-9e8b-b4656326cfb2"; + // Path to the events used by ZoomIt + const wchar_t ZOOMIT_REFRESH_SETTINGS_EVENT[] = L"Local\\PowerToysZoomIt-RefreshSettingsEvent-f053a563-d519-4b0d-8152-a54489c13324"; + const wchar_t ZOOMIT_EXIT_EVENT[] = L"Local\\PowerToysZoomIt-ExitEvent-36641ce6-df02-4eac-abea-a3fbf9138220"; + // Max DWORD for key code to disable keys. const DWORD VK_DISABLED = 0x100; } diff --git a/src/common/logger/logger.cpp b/src/common/logger/logger.cpp index 9587b97743af..709e634af649 100644 --- a/src/common/logger/logger.cpp +++ b/src/common/logger/logger.cpp @@ -85,7 +85,7 @@ void Logger::init(std::string loggerName, std::wstring logFilePath, std::wstring { // todo: that message should be shown from init caller and strings should be localized MessageBoxW(NULL, - L"Logger can not be initialized", + L"Logger cannot be initialized", L"PowerToys", MB_OK | MB_ICONERROR); diff --git a/src/common/logger/logger_settings.h b/src/common/logger/logger_settings.h index e20bc999d9c5..dab7ad64a22e 100644 --- a/src/common/logger/logger_settings.h +++ b/src/common/logger/logger_settings.h @@ -76,6 +76,7 @@ struct LogSettings inline const static std::wstring workspacesWindowArrangerLogPath = L"workspaces-window-arranger-log.txt"; inline const static std::string workspacesSnapshotToolLoggerName = "workspaces-snapshot-tool"; inline const static std::wstring workspacesSnapshotToolLogPath = L"workspaces-snapshot-tool-log.txt"; + inline const static std::string zoomItLoggerName = "zoom-it"; inline const static int retention = 30; std::wstring logLevel; LogSettings(); diff --git a/src/common/notifications/BackgroundActivator/pch.h b/src/common/notifications/BackgroundActivator/pch.h index 83ef612465bb..17b97f557d83 100644 --- a/src/common/notifications/BackgroundActivator/pch.h +++ b/src/common/notifications/BackgroundActivator/pch.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/src/common/notifications/notifications.cpp b/src/common/notifications/notifications.cpp index 8b245cfa7962..0190e088b243 100644 --- a/src/common/notifications/notifications.cpp +++ b/src/common/notifications/notifications.cpp @@ -4,7 +4,7 @@ #include "utils/com_object_factory.h" #include "utils/window.h" -#include +#include #include #include #include diff --git a/src/common/sysinternals/Eula/Eula.txt b/src/common/sysinternals/Eula/Eula.txt new file mode 100644 index 000000000000..8efa71167cc3 --- /dev/null +++ b/src/common/sysinternals/Eula/Eula.txt @@ -0,0 +1,75 @@ +Sysinternals Software License Terms +These license terms are an agreement between Sysinternals (a wholly owned subsidiary of Microsoft Corporation) and you. Please read them. They apply to the software you are downloading from technet.microsoft.com/sysinternals, which includes the media on which you received it, if any. The terms also apply to any Sysinternals +* updates, +* supplements, +* Internet-based services, +* and support services +for this software, unless other terms accompany those items. If so, those terms apply. +BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE. +If you comply with these license terms, you have the rights below. + +Installation and User Rights + +You may install and use any number of copies of the software on your devices. + +Scope of License + +The software is licensed, not sold. This agreement only gives you some rights to use the software. Sysinternals reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not +* work around any technical limitations in the software; +* reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation; +* make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation; +* publish the software for others to copy; +* rent, lease or lend the software; +* transfer the software or this agreement to any third party; or +* use the software for commercial software hosting services. + +Sensitive Information + +Please be aware that, similar to other debug tools that capture “process state” information, files saved by Sysinternals tools may include personally identifiable or other sensitive information (such as usernames, passwords, paths to files accessed, and paths to registry accessed). By using this software, you acknowledge that you are aware of this and take sole responsibility for any personally identifiable or other sensitive information provided to Microsoft or any other party through your use of the software. + +Documentation + +Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes. + +Export Restrictions + +The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see www.microsoft.com/exporting . + +Support Services + +Because this software is "as is," we may not provide support services for it. + +Entire Agreement + +This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. + +Applicable Law + +United States . If you acquired the software in the United States , Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort. +Outside the United States . If you acquired the software in any other country, the laws of that country apply. + +Legal Effect + +This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so. + +Disclaimer of Warranty + +The software is licensed "as-is." You bear the risk of using it. Sysinternals gives no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this agreement cannot change. To the extent permitted under your local laws, sysinternals excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement. + +Limitation on and Exclusion of Remedies and Damages + +You can recover from sysinternals and its suppliers only direct damages up to U.S. $5.00. You cannot recover any other damages, including consequential, lost profits, special, indirect or incidental damages. +This limitation applies to +* anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and +* claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. + +It also applies even if Sysinternals knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages. +Please note: As this software is distributed in Quebec , Canada , some of the clauses in this agreement are provided below in French. +Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français. +EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Sysinternals n'accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection dues consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d'adéquation à un usage particulier et d'absence de contrefaçon sont exclues. +LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. Vous pouvez obtenir de Sysinternals et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. +Cette limitation concerne : +tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et +les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d'une autre faute dans la limite autorisée par la loi en vigueur. +Elle s'applique également, même si Sysinternals connaissait ou devrait connaître l'éventualité d'un tel dommage. Si votre pays n'autorise pas l'exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l'exclusion ci-dessus ne s'appliquera pas à votre égard. +EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d'autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas. diff --git a/src/common/sysinternals/Eula/eula.c b/src/common/sysinternals/Eula/eula.c new file mode 100644 index 000000000000..eaf35e9be54c --- /dev/null +++ b/src/common/sysinternals/Eula/eula.c @@ -0,0 +1,702 @@ +#pragma once + +#pragma warning( disable: 4996) + +#include +#include +#include +#include +#include +#include +#include +#include "Eula.h" +#include "dll.h" + +#define IDC_TEXT 500 +#define IDC_PRINT 501 +#define IDC_TEXT1 502 + +static const char * EulaText[] = { +"{\\rtf1\\ansi\\ansicpg1252\\deff0\\nouicompat\\deflang1033{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Tahoma;}{\\f1\\fnil\\fcharset0 Calibri;}}", +"{\\colortbl ;\\red0\\green0\\blue255;\\red0\\green0\\blue0;}", +"{\\*\\generator Riched20 10.0.10240}\\viewkind4\\uc1 ", +"\\pard\\brdrb\\brdrs\\brdrw10\\brsp20 \\sb120\\sa120\\b\\f0\\fs24 SYSINTERNALS SOFTWARE LICENSE TERMS\\fs28\\par", +"\\pard\\sb120\\sa120\\b0\\fs19 These license terms are an agreement between Sysinternals (a wholly owned subsidiary of Microsoft Corporation) and you. Please read them. They apply to the software you are downloading from Sysinternals.com, which includes the media on which you received it, if any. The terms also apply to any Sysinternals\\par", +"\\pard\\fi-363\\li720\\sb120\\sa120\\tx720\\'b7\\tab updates,\\par", +"\\pard\\fi-363\\li720\\sb120\\sa120\\'b7\\tab supplements,\\par", +"\\'b7\\tab Internet-based services, and \\par", +"\\'b7\\tab support services\\par", +"\\pard\\sb120\\sa120 for this software, unless other terms accompany those items. If so, those terms apply.\\par", +"\\b BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE.\\par", +"\\pard\\brdrt\\brdrs\\brdrw10\\brsp20 \\sb120\\sa120 If you comply with these license terms, you have the rights below.\\par", +"\\pard\\fi-357\\li357\\sb120\\sa120\\tx360\\fs20 1.\\tab\\fs19 INSTALLATION AND USE RIGHTS. \\b0 You may install and use any number of copies of the software on your devices.\\b\\par", +"\\caps\\fs20 2.\\tab\\fs19 Scope of License\\caps0 .\\b0 The software is licensed, not sold. This agreement only gives you some rights to use the software. Sysinternals reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not\\b\\par", +"\\pard\\fi-363\\li720\\sb120\\sa120\\tx720\\b0\\'b7\\tab work around any technical limitations in the binary versions of the software;\\par", +"\\pard\\fi-363\\li720\\sb120\\sa120\\'b7\\tab reverse engineer, decompile or disassemble the binary versions of the software, except and only to the extent that applicable law expressly permits, despite this limitation;\\par", +"\\'b7\\tab make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation;\\par", +"\\'b7\\tab publish the software for others to copy;\\par", +"\\'b7\\tab rent, lease or lend the software;\\par", +"\\'b7\\tab transfer the software or this agreement to any third party; or\\par", +"\\'b7\\tab use the software for commercial software hosting services.\\par", +"\\pard\\fi-357\\li357\\sb120\\sa120\\tx360\\b\\fs20 3.\\tab SENSITIVE INFORMATION. \\b0 Please be aware that, similar to other debug tools that capture \\ldblquote process state\\rdblquote information, files saved by Sysinternals tools may include personally identifiable or other sensitive information (such as usernames, passwords, paths to files accessed, and paths to registry accessed). By using this software, you acknowledge that you are aware of this and take sole responsibility for any personally identifiable or other sensitive information provided to Microsoft or any other party through your use of the software.\\b\\par", +"5. \\tab\\fs19 DOCUMENTATION.\\b0 Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.\\b\\par", +"\\caps\\fs20 6.\\tab\\fs19 Export Restrictions\\caps0 .\\b0 The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see {\\cf1\\ul{\\field{\\*\\fldinst{HYPERLINK www.microsoft.com/exporting }}{\\fldrslt{www.microsoft.com/exporting}}}}\\cf1\\ul\\f0\\fs19 <{{\\field{\\*\\fldinst{HYPERLINK \"http://www.microsoft.com/exporting\"}}{\\fldrslt{http://www.microsoft.com/exporting}}}}\\f0\\fs19 >\\cf0\\ulnone .\\b\\par", +"\\caps\\fs20 7.\\tab\\fs19 SUPPORT SERVICES.\\caps0 \\b0 Because this software is \"as is, \" we may not provide support services for it.\\b\\par", +"\\caps\\fs20 8.\\tab\\fs19 Entire Agreement.\\b0\\caps0 This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.\\par", +"\\pard\\keepn\\fi-360\\li360\\sb120\\sa120\\tx360\\cf2\\b\\caps\\fs20 9.\\tab\\fs19 Applicable Law\\caps0 .\\par", +"\\pard\\fi-363\\li720\\sb120\\sa120\\tx720\\cf0\\fs20 a.\\tab\\fs19 United States.\\b0 If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.\\b\\par", +"\\pard\\fi-363\\li720\\sb120\\sa120\\fs20 b.\\tab\\fs19 Outside the United States.\\b0 If you acquired the software in any other country, the laws of that country apply.\\b\\par", +"\\pard\\fi-357\\li357\\sb120\\sa120\\tx360\\caps\\fs20 10.\\tab\\fs19 Legal Effect.\\b0\\caps0 This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.\\b\\caps\\par", +"\\fs20 11.\\tab\\fs19 Disclaimer of Warranty.\\caps0 \\caps The software is licensed \"as - is.\" You bear the risk of using it. SYSINTERNALS gives no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this agreement cannot change. To the extent permitted under your local laws, SYSINTERNALS excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement.\\par", +"\\pard\\fi-360\\li360\\sb120\\sa120\\tx360\\fs20 12.\\tab\\fs19 Limitation on and Exclusion of Remedies and Damages. You can recover from SYSINTERNALS and its suppliers only direct damages up to U.S. $5.00. You cannot recover any other damages, including consequential, lost profits, special, indirect or incidental damages.\\par", +"\\pard\\li357\\sb120\\sa120\\b0\\caps0 This limitation applies to\\par", +"\\pard\\fi-363\\li720\\sb120\\sa120\\tx720\\'b7\\tab anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and\\par", +"\\pard\\fi-363\\li720\\sb120\\sa120\\'b7\\tab claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.\\par", +"\\pard\\li360\\sb120\\sa120 It also applies even if Sysinternals knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.\\par", +"\\pard\\b Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.\\par", +"\\pard\\sb240\\lang1036 Remarque : Ce logiciel \\'e9tant distribu\\'e9 au Qu\\'e9bec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en fran\\'e7ais.\\par", +"\\pard\\sb120\\sa120 EXON\\'c9RATION DE GARANTIE.\\b0 Le logiciel vis\\'e9 par une licence est offert \\'ab tel quel \\'bb. Toute utilisation de ce logiciel est \\'e0 votre seule risque et p\\'e9ril. Sysinternals n'accorde aucune autre garantie expresse. Vous pouvez b\\'e9n\\'e9ficier de droits additionnels en vertu du droit local sur la protection dues consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualit\\'e9 marchande, d'ad\\'e9quation \\'e0 un usage particulier et d'absence de contrefa\\'e7on sont exclues.\\par", +"\\pard\\keepn\\sb120\\sa120\\b LIMITATION DES DOMMAGES-INT\\'c9R\\'caTS ET EXCLUSION DE RESPONSABILIT\\'c9 POUR LES DOMMAGES.\\b0 Vous pouvez obtenir de Sysinternals et de ses fournisseurs une indemnisation en cas de dommages directs uniquement \\'e0 hauteur de 5,00 $ US. Vous ne pouvez pr\\'e9tendre \\'e0 aucune indemnisation pour les autres dommages, y compris les dommages sp\\'e9ciaux, indirects ou accessoires et pertes de b\\'e9n\\'e9fices.\\par", +"\\lang1033 Cette limitation concerne :\\par", +"\\pard\\keepn\\fi-360\\li720\\sb120\\sa120\\tx720\\lang1036\\'b7\\tab tout ce qui est reli\\'e9 au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et\\par", +"\\pard\\fi-363\\li720\\sb120\\sa120\\tx720\\'b7\\tab les r\\'e9clamations au titre de violation de contrat ou de garantie, ou au titre de responsabilit\\'e9 stricte, de n\\'e9gligence ou d'une autre faute dans la limite autoris\\'e9e par la loi en vigueur.\\par", +"\\pard\\sb120\\sa120 Elle s'applique \\'e9galement, m\\'eame si Sysinternals connaissait ou devrait conna\\'eetre l'\\'e9ventualit\\'e9 d'un tel dommage. Si votre pays n'autorise pas l'exclusion ou la limitation de responsabilit\\'e9 pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l'exclusion ci-dessus ne s'appliquera pas \\'e0 votre \\'e9gard.\\par", +"\\b EFFET JURIDIQUE.\\b0 Le pr\\'e9sent contrat d\\'e9crit certains droits juridiques. Vous pourriez avoir d'autres droits pr\\'e9vus par les lois de votre pays. Le pr\\'e9sent contrat ne modifie pas les droits que vous conf\\'e8rent les lois de votre pays si celles-ci ne le permettent pas.\\b\\par", +"\\pard\\b0\\fs20\\lang1033\\par", +"\\pard\\sa200\\sl276\\slmult1\\f1\\fs22\\lang9\\par", +"}", +NULL +}; + +static const wchar_t *Raw_EulaText = L"SYSINTERNALS SOFTWARE LICENSE TERMS\nThese license terms are an agreement between Sysinternals(a wholly owned subsidiary of Microsoft Corporation) and you.Please read them.They apply to the software you are downloading from technet.microsoft.com / sysinternals, which includes the media on which you received it, if any.The terms also apply to any Sysinternals\n* updates,\n*supplements,\n*Internet - based services,\n*and support services\nfor this software, unless other terms accompany those items.If so, those terms apply.\nBY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE.\n\nIf you comply with these license terms, you have the rights below.\nINSTALLATION AND USER RIGHTS\nYou may install and use any number of copies of the software on your devices.\n\nSCOPE OF LICENSE\nThe software is licensed, not sold.This agreement only gives you some rights to use the software.Sysinternals reserves all other rights.Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement.In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways.You may not\n* work around any technical limitations in the software;\n*reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;\n*make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation;\n*publish the software for others to copy;\n*rent, lease or lend the software;\n*transfer the software or this agreement to any third party; or\n* use the software for commercial software hosting services.\n\nSENSITIVE INFORMATION\nPlease be aware that, similar to other debug tools that capture “process state” information, files saved by Sysinternals tools may include personally identifiable or other sensitive information(such as usernames, passwords, paths to files accessed, and paths to registry accessed).By using this software, you acknowledge that you are aware of this and take sole responsibility for any personally identifiable or other sensitive information provided to Microsoft or any other party through your use of the software.\n\nDOCUMENTATION\nAny person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.\n\nEXPORT RESTRICTIONS\nThe software is subject to United States export laws and regulations.You must comply with all domestic and international export laws and regulations that apply to the software.These laws include restrictions on destinations, end users and end use.For additional information, see www.microsoft.com / exporting .\n\nSUPPORT SERVICES\nBecause this software is \"as is, \" we may not provide support services for it.\n\nENTIRE AGREEMENT\nThis agreement, and the terms for supplements, updates, Internet - based services and support services that you use, are the entire agreement for the software and support services.\n\nAPPLICABLE LAW\nUnited States.If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles.The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.\nOutside the United States.If you acquired the software in any other country, the laws of that country apply.\n\nLEGAL EFFECT\nThis agreement describes certain legal rights.You may have other rights under the laws of your country.You may also have rights with respect to the party from whom you acquired the software.This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.\n\nDISCLAIMER OF WARRANTY\nThe software is licensed \"as - is.\" You bear the risk of using it.Sysinternals gives no express warranties, guarantees or conditions.You may have additional consumer rights under your local laws which this agreement cannot change.To the extent permitted under your local laws, sysinternals excludes the implied warranties of merchantability, fitness for a particular purpose and non - infringement.\n\nLIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES\nYou can recover from sysinternals and its suppliers only direct damages up to U.S.$5.00.You cannot recover any other damages, including consequential, lost profits, special, indirect or incidental damages.\nThis limitation applies to\n* anything related to the software, services, content(including code) on third party Internet sites, or third party programs; and\n* claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.\nIt also applies even if Sysinternals knew or should have known about the possibility of the damages.The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.\nPlease note : As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.\nRemarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci - dessous en français.\n EXONÉRATION DE GARANTIE.Le logiciel visé par une licence est offert « tel quel ».Toute utilisation de ce logiciel est à votre seule risque et péril.Sysinternals n'accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection dues consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d'adéquation à un usage particulier et d'absence de contrefaçon sont exclues.\n LIMITATION DES DOMMAGES - INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES.Vous pouvez obtenir de Sysinternals et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5, 00 $ US.Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices.\n\n Cette limitation concerne :\ntout ce qui est relié au logiciel, aux services ou au contenu(y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers; et\nles réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d'une autre faute dans la limite autorisée par la loi en vigueur.\n\nElle s'applique également, même si Sysinternals connaissait ou devrait connaître l'éventualité d'un tel dommage. Si votre pays n'autorise pas l'exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l'exclusion ci - dessus ne s'appliquera pas à votre égard.\nEFFET JURIDIQUE.Le présent contrat décrit certains droits juridiques.Vous pourriez avoir d'autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas.\n\n"; + +BOOL IsEulaRegkeyAdded(const TCHAR * ToolName); + +static BOOL EulaCenter( HWND hwndChild, HWND hwndParent ) +{ + RECT rcChild, rcParent; + int cxChild, cyChild, cxParent, cyParent; + int cxScreen, cyScreen, xNew, yNew; + HDC hdc; + + // Get the Height and Width of the child window + GetWindowRect(hwndChild, &rcChild); + cxChild = rcChild.right - rcChild.left; + cyChild = rcChild.bottom - rcChild.top; + + // Get the Height and Width of the parent window + GetWindowRect(hwndParent, &rcParent); + cxParent = rcParent.right - rcParent.left; + cyParent = rcParent.bottom - rcParent.top; + + // Get the display limits + hdc = GetDC(hwndChild); + cxScreen = GetDeviceCaps(hdc, HORZRES); + cyScreen = GetDeviceCaps(hdc, VERTRES); + ReleaseDC(hwndChild, hdc); + + // Calculate new X position, then adjust for screen + xNew = rcParent.left + ((cxParent - cxChild) / 2); + if (xNew < 0) + { + xNew = 0; + } + else if ((xNew + cxChild) > cxScreen) + { + xNew = cxScreen - cxChild; + } + + // Calculate new Y position, then adjust for screen + yNew = rcParent.top + ((cyParent - cyChild) / 2); + if (yNew < 0) + { + yNew = 0; + } + else if ((yNew + cyChild) > cyScreen) + { + yNew = cyScreen - cyChild; + } + + // Set it, and return + return SetWindowPos(hwndChild, + NULL, + xNew, yNew, + 0, 0, + SWP_NOSIZE | SWP_NOZORDER); +} + + + +static BOOL PrintRichedit( HWND hRichedit ) +{ + // Get the printer. + PRINTDLG pd = { 0 }; + + pd.lStructSize = sizeof pd; + pd.hwndOwner = hRichedit; + pd.hInstance = GetModuleHandle(NULL); + pd.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION | PD_PRINTSETUP; + if ( !PrintDlg( &pd ) ) + return FALSE; + + { + HCURSOR oldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) ); + int nHorzRes = GetDeviceCaps( pd.hDC, HORZRES ); + int nVertRes = GetDeviceCaps( pd.hDC, VERTRES ); + int nLogPixelsX = GetDeviceCaps( pd.hDC, LOGPIXELSX ); + int nLogPixelsY = GetDeviceCaps( pd.hDC, LOGPIXELSY ); + FORMATRANGE fr = { 0 }; + DOCINFO di = { 0 }; + int TotalLength; + + // Ensure the printer DC is in MM_TEXT mode. + SetMapMode( pd.hDC, MM_TEXT ); + + // Rendering to the same DC we are measuring. + fr.hdc = pd.hDC; + fr.hdcTarget = pd.hDC; + + // Set up the page. + fr.rcPage.top = 0; + fr.rcPage.left = 0; + fr.rcPage.bottom = (nVertRes/nLogPixelsY) * 1440; + fr.rcPage.right = (nHorzRes/nLogPixelsX) * 1440; + + // Set up 1" margins all around. + fr.rc = fr.rcPage; + InflateRect( &fr.rc, -1440, -1440 ); + + // Default the range of text to print as the entire document. + fr.chrg.cpMin = 0; + fr.chrg.cpMax = -1; + + // Set up the print job (standard printing stuff here). + di.cbSize = sizeof di; + di.lpszDocName = _T("Sysinternals License"); + + // Start the document. + StartDoc( pd.hDC, &di ); + + // Find out real size of document in characters. + TotalLength = (int) SendMessage ( hRichedit, WM_GETTEXTLENGTH, 0, 0 ); + for (;;) { + int NextPage; + + // Start the page. + StartPage( pd.hDC ); + + // Print as much text as can fit on a page. The return value is + // the index of the first character on the next page. + NextPage = (int) SendMessage( hRichedit, EM_FORMATRANGE, TRUE, (LPARAM)&fr ); + + // Print last page. + EndPage( pd.hDC ); + + if ( NextPage >= TotalLength ) + break; + + // Adjust the range of characters to start printing at the first character of the next page. + fr.chrg.cpMin = NextPage; + fr.chrg.cpMax = -1; + } + + // Tell the control to release cached information. + SendMessage( hRichedit, EM_FORMATRANGE, 0, (LPARAM)NULL ); + EndDoc( pd.hDC ); + + SetCursor( oldCursor ); + } + + return TRUE; +} + +// combine all text strings into a single string +char * GetEulaText() +{ + char * text; + DWORD len = 1; + int i; + for ( i = 0; EulaText[i]; ++i ) + len += (DWORD) strlen( EulaText[i] ); + text = (char *) malloc( len ); + len = 0; + for ( i = 0; EulaText[i]; ++i ) { + strcpy( text+len, EulaText[i] ); + len += (DWORD) strlen( EulaText[i] ); + } + text[len] = 0; + return text; +} + +DWORD CALLBACK StreamCallback( DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb ) +{ + const char ** ptr = (const char **) dwCookie; + LONG_PTR len = strlen(*ptr); + if ( cb > len ) + cb = (int) len; + memcpy( pbBuff, *ptr, cb ); + *pcb = cb; + *ptr += cb; + return 0; +} + +static INT_PTR CALLBACK EulaProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + switch ( uMsg ) { + case WM_INITDIALOG: + { + TCHAR title[MAX_PATH]; + char * text = GetEulaText(); + char * textptr = text; + EDITSTREAM stream = { 0, 0, StreamCallback }; + stream.dwCookie = (DWORD_PTR) &textptr; + _stprintf_s( title, MAX_PATH, _T("%s License Agreement"), (TCHAR *) lParam ); + SetWindowText( hwndDlg, title ); + + // enter RTF into edit box + SendMessage( GetDlgItem(hwndDlg,IDC_TEXT), EM_EXLIMITTEXT, 0, 1024*1024 ); + SendMessage( GetDlgItem(hwndDlg,IDC_TEXT), EM_STREAMIN, SF_RTF, (LPARAM)&stream ); + free( text ); + } + return TRUE; + + case WM_CTLCOLORSTATIC: + // force background of read-only text window to be white + if ( (HWND)lParam == GetDlgItem( hwndDlg, IDC_TEXT) ) { + return (INT_PTR)GetSysColorBrush( COLOR_WINDOW ); + } + break; + + case WM_COMMAND: + switch( LOWORD( wParam )) { + case IDOK: + EndDialog( hwndDlg, TRUE ); + return TRUE; + case IDCANCEL: + EndDialog( hwndDlg, FALSE ); + return TRUE; + case IDC_PRINT: + PrintRichedit( GetDlgItem(hwndDlg,IDC_TEXT) ); + return TRUE; + } + break; + } + return FALSE; +} + + +static WORD * Align2( WORD * pos ) +{ + return (WORD *)(((DWORD_PTR)pos + 1) & ~((DWORD_PTR) 1)); +} +static WORD * Align4( WORD * pos ) +{ + return (WORD *)(((DWORD_PTR)pos + 3) & ~((DWORD_PTR) 3)); +} + +static int CopyText( WORD * pos, const WCHAR * text ) +{ + int len = (int) wcslen( text ) + 1; + wcscpy( (PWCHAR) pos, text ); + return len; +} + +BOOL ShowEulaInternal( const TCHAR * ToolName, DWORD eulaAccepted ) +{ +#if !defined(SYSMON_SHARED) + HKEY hKey = NULL; + TCHAR keyName[MAX_PATH]; + + _stprintf_s( keyName, MAX_PATH, _T("Software\\Sysinternals\\%s"), ToolName ); + + // + // check the regkey value if no -accepteula switch append + // + if (!eulaAccepted) + { + eulaAccepted = IsEulaRegkeyAdded(ToolName); + } +#endif + + if( !eulaAccepted ) { + if (IsIoTEdition()) + { + eulaAccepted = ShowEulaConsole(); // display Eula to console and prompt for Eula Accepted. + { + } + } + else if (IsRemoteOnlyEdition() || IsRunningRemotely()) // Nano and in remote session will not be able to accept eula from prompt + { + ShowEulaConsoleNoPrompt(); + } + else + { + DLGTEMPLATE * dlg = (DLGTEMPLATE *)LocalAlloc(LPTR, 1000); + WORD * extra = (WORD *)(dlg + 1); + DLGITEMTEMPLATE * item; + +#if defined(SYSMON_SHARED) + printf( "Displaying EULA Gui dialog box ... (use -accepteula to avoid).\n" ); +#endif + + LoadLibrarySafe(_T("Riched32.dll"), DLL_LOAD_LOCATION_SYSTEM ); // Richedit 1.0 library + + // header + dlg->style = DS_MODALFRAME | DS_CENTER | DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_NOFAILCREATE; + dlg->x = 0; + dlg->y = 0; + dlg->cx = 312; + dlg->cy = 180; + dlg->cdit = 0; // number of controls + + *extra++ = 0; // menu + *extra++ = 0; // class + extra += CopyText(extra, L"License Agreement"); + *extra++ = 8; // font size + extra += CopyText(extra, L"MS Shell Dlg"); + + // Command-line message + item = (DLGITEMTEMPLATE *)Align4(extra); + item->x = 7; + item->y = 3; + item->cx = 298; + item->cy = 14; + item->id = IDC_TEXT1; + item->style = WS_CHILD | WS_VISIBLE; + extra = (WORD *)(item + 1); + *extra++ = 0xFFFF; // class is ordinal + *extra++ = 0x0082; // class is static + extra += CopyText(extra, L"You can also use the /accepteula command-line switch to accept the EULA."); + *extra++ = 0; // creation data + dlg->cdit++; + + // Agree button + item = (DLGITEMTEMPLATE *)Align4(extra); + item->x = 201; + item->y = 159; + item->cx = 50; + item->cy = 14; + item->id = IDOK; + item->style = BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP; // | WS_DEFAULT; + extra = (WORD *)(item + 1); + *extra++ = 0xFFFF; // class is ordinal + *extra++ = 0x0080; // class is button + extra += CopyText(extra, L"&Agree"); + *extra++ = 0; // creation data + dlg->cdit++; + + // Decline button + item = (DLGITEMTEMPLATE *)Align4(extra); + item->x = 255; + item->y = 159; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; + item->style = BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP; + extra = (WORD *)(item + 1); + *extra++ = 0xFFFF; // class is ordinal + *extra++ = 0x0080; // class is button + extra += CopyText(extra, L"&Decline"); + *extra++ = 0; // creation data + dlg->cdit++; + + // Print button + item = (DLGITEMTEMPLATE *)Align4(extra); + item->x = 7; + item->y = 159; + item->cx = 50; + item->cy = 14; + item->id = IDC_PRINT; + item->style = BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP; + extra = (WORD *)(item + 1); + *extra++ = 0xFFFF; // class is ordinal + *extra++ = 0x0080; // class is button + extra += CopyText(extra, L"&Print"); + *extra++ = 0; // creation data + dlg->cdit++; + + // Edit box + item = (DLGITEMTEMPLATE *)Align4(extra); + item->x = 7; + item->y = 14; + item->cx = 298; + item->cy = 140; + item->id = IDC_TEXT; + item->style = WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP; + extra = (WORD *)(item + 1); + extra += CopyText(extra, L"RICHEDIT"); + extra += CopyText(extra, L"&Decline"); + *extra++ = 0; // creation data + dlg->cdit++; + + eulaAccepted = (DWORD)DialogBoxIndirectParam(NULL, dlg, NULL, EulaProc, (LPARAM)ToolName); + LocalFree(dlg); + } + } +#if !defined(SYSMON_SHARED) + if ( eulaAccepted ) { + if (RegCreateKey(HKEY_CURRENT_USER, keyName, &hKey) == ERROR_SUCCESS) { + RegSetValueEx(hKey, _T("EulaAccepted"), 0, REG_DWORD, (BYTE *)&eulaAccepted, sizeof(eulaAccepted)); + RegCloseKey(hKey); + } + } +#endif + + return eulaAccepted != 0; +} + +BOOL ShowEulaW( const TCHAR * ToolName, int *argc, PWCHAR argv[] ) +{ + DWORD eulaAccepted = 0; + int i; + + if ( argc == NULL || argv == NULL ) { + typedef LPWSTR * (WINAPI * type_CommandLineToArgvW)( LPCWSTR lpCmdLine, int *pNumArgs ); + type_CommandLineToArgvW pCommandLineToArgvW = (type_CommandLineToArgvW) GetProcAddress( LoadLibrarySafe(_T("Shell32.dll"), DLL_LOAD_LOCATION_SYSTEM), "CommandLineToArgvW" ); + if ( pCommandLineToArgvW ) { + static int argc2; + argc = &argc2; + argv = (*pCommandLineToArgvW)( GetCommandLineW(), argc ); + } else { + argc = NULL; + } + } + + + // + // See if its accepted via command line switch + // + if( argc ) { + + for( i = 0; i < *argc; i++ ) { + + eulaAccepted = (!_wcsicmp( argv[i], L"/accepteula") || + !_wcsicmp( argv[i], L"-accepteula")); + if( eulaAccepted ) { + + for( ; i < *argc - 1; i++ ) { + + argv[i] = argv[i+1]; + } + (*argc)--; + break; + } + } + } + if( ShowEulaInternal( ToolName, eulaAccepted )) { + + eulaAccepted = 1; + } + return eulaAccepted != 0; +} + + +BOOL ShowEula( const TCHAR * ToolName, int *argc, PTCHAR argv[] ) +{ + DWORD eulaAccepted = 0; + int i; + + if ( argc == NULL || argv == NULL ) { + return ShowEulaW( ToolName, NULL, NULL ); + } + + // + // See if its accepted via command line switch + // + if( argc ) { + + for( i = 0; i < *argc; i++ ) { + + eulaAccepted = (!_tcsicmp( argv[i], _T("/accepteula")) || + !_tcsicmp( argv[i], _T("-accepteula"))); + if( eulaAccepted ) { + + for( ; i < *argc - 1; i++ ) { + + argv[i] = argv[i+1]; + } + (*argc)--; + break; + } + } + } + if( ShowEulaInternal( ToolName, eulaAccepted )) { + + eulaAccepted = 1; + } + return eulaAccepted != 0; +} + +// Determine whether we are on the IoT SKU by looking at the ProductName. +BOOL IsIoTEdition() +{ + HKEY hKey = NULL; + wchar_t ProductName[MAX_PATH]; + BOOL bRet = FALSE; // assume "not" IoT Edition + DWORD dwSize = sizeof(ProductName); + DWORD type = 0; + + if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\windows nt\\currentversion"), &hKey)) + { + if (ERROR_SUCCESS == RegQueryValueExW(hKey, L"ProductName", 0, &type, (LPBYTE)ProductName, &dwSize)) + { + if (!_wcsicmp(L"iotuap", ProductName)) + bRet = TRUE; + } + RegCloseKey(hKey); + } + + return bRet; +} + +// Determine whether we are on the remote only edition, where we cannot prompt for user input. +BOOL IsRemoteOnlyEdition() +{ + HKEY hKey = NULL; + DWORD dwNanoServer = 0; + BOOL bRet = FALSE; + DWORD dwSize = sizeof(dwNanoServer); + DWORD type = 0; + + // Currently Nano is the only remote only edtion. + if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Server\\ServerLevels"), &hKey)) + { + if (ERROR_SUCCESS == RegQueryValueEx(hKey, _T("NanoServer"), 0, &type, (LPBYTE)&dwNanoServer, &dwSize)) + { + if (type == REG_DWORD && dwNanoServer == 1) + bRet = TRUE; + } + RegCloseKey(hKey); + } + + return bRet; +} + +BOOL IsRunningRemotely() +{ + // running from a remote session will not support input interaction + DWORD fileType = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)); + return fileType == FILE_TYPE_PIPE; +} + +DWORD ShowEulaConsole() +{ + DWORD dwRet = 0; + char ch; + BOOLEAN eulaAcknowledged = FALSE; + + wprintf(Raw_EulaText); + + while( eulaAcknowledged != TRUE ) + { + printf("Accept Eula (Y/N)?"); + ch = (char) _getch(); + printf("%c\n", ch); + if ('y' == ch || 'Y' == ch) + { + dwRet = 1; // EULA Accepted. + eulaAcknowledged = TRUE; + } + + if ('n' == ch || 'N' == ch) + { + // EULA not accepted. + eulaAcknowledged = TRUE; + } + } + return dwRet; +} + +void ShowEulaConsoleNoPrompt() +{ + wprintf_s(L"%ls", Raw_EulaText); + wprintf_s(L"This is the first run of this program. You must accept EULA to continue.\n"); + wprintf_s(L"Use -accepteula to accept EULA.\n\n"); + + // exit here to avoid printing the misleading "Eula declined". + exit(1); +} + +BOOL IsEulaAcceptedValueExist(HKEY hKeyRoot, LPCTSTR lpSubKey) +{ + HKEY hKey = NULL; + DWORD length; + DWORD eulaAccepted = 0; + DWORD ret; + + // + // check if it is set by external channel for all tools + // assuming external channel do not set to WOW6432Node + // + if (RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS) + { + length = sizeof(eulaAccepted); + ret = RegQueryValueEx(hKey, _T("EulaAccepted"), NULL, NULL, (LPBYTE)&eulaAccepted, &length); + RegCloseKey(hKey); + + if (ret == ERROR_SUCCESS && eulaAccepted) + { + return TRUE; + } + } + + return FALSE; +} + +BOOL IsEulaRegkeyAdded(const TCHAR * ToolName) +{ + TCHAR perToolRegKey[MAX_PATH]; + PTCHAR suiteRegKey = _T("Software\\Sysinternals"); + + _stprintf_s(perToolRegKey, MAX_PATH, _T("%s\\%s"), suiteRegKey, ToolName); + + // + // check if it is set by external channel for all tools + // assuming external channel do not set to WOW6432Node + // + if (IsEulaAcceptedValueExist(HKEY_LOCAL_MACHINE, suiteRegKey) || + IsEulaAcceptedValueExist(HKEY_CURRENT_USER, suiteRegKey)) + { + return TRUE; + } + + // + // per tool check + // + if (IsEulaAcceptedValueExist(HKEY_CURRENT_USER, perToolRegKey)) + { + return TRUE; + } + + return FALSE; +} + +BOOL IsEulaSwitchAppended(int *argc, PTCHAR argv[]) +{ + DWORD eulaAccepted = 0; + int i; + + // + // See if its accepted via command line switch + // + if (*argc > 1) { + for (i = 1; i < *argc; i++) { + eulaAccepted = (!_tcsicmp(argv[i], _T("/accepteula")) || + !_tcsicmp(argv[i], _T("-accepteula"))); + if (eulaAccepted) { + break; + } + } + } + + return eulaAccepted; +} + +// +// Determine if Eula is accepted, either already have regkey added +// or have -accepteula switch appended +// +BOOL IsEulaAccepted(const TCHAR * ToolName, int *argc, PTCHAR argv[]) +{ + return IsEulaRegkeyAdded(ToolName) || IsEulaSwitchAppended(argc, argv); +} diff --git a/src/common/sysinternals/Eula/eula.h b/src/common/sysinternals/Eula/eula.h new file mode 100644 index 000000000000..450031583e95 --- /dev/null +++ b/src/common/sysinternals/Eula/eula.h @@ -0,0 +1,17 @@ +#ifdef __cplusplus +extern "C" { +#endif + + +BOOL ShowEulaW( const TCHAR * ToolName, int *argc, PWCHAR argv[] ); +BOOL ShowEula( const TCHAR * ToolName, int *argc, TCHAR *argv[] ); +DWORD ShowEulaConsole(); +void ShowEulaConsoleNoPrompt(); +BOOL IsIoTEdition(); +BOOL IsRemoteOnlyEdition(); +BOOL IsRunningRemotely(); +BOOL IsEulaAccepted(const TCHAR * ToolName, int *argc, PTCHAR argv[]); + +#ifdef __cplusplus +} +#endif diff --git a/src/common/sysinternals/Eula/eula.rtf b/src/common/sysinternals/Eula/eula.rtf new file mode 100644 index 000000000000..4f8c495bf30d --- /dev/null +++ b/src/common/sysinternals/Eula/eula.rtf @@ -0,0 +1,76 @@ +{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 Tahoma;}{\f1\fnil\fcharset0 Calibri;}} +{\colortbl ;\red0\green0\blue255;\red0\green0\blue0;} +{\*\generator Riched20 10.0.10240}\viewkind4\uc1 +\pard\brdrb\brdrs\brdrw10\brsp20 \sb120\sa120\b\f0\fs24 SYSINTERNALS SOFTWARE LICENSE TERMS\fs28\par + +\pard\sb120\sa120\b0\fs19 These license terms are an agreement between Sysinternals (a wholly owned subsidiary of Microsoft Corporation) and you. Please read them. They apply to the software you are downloading from Sysinternals.com, which includes the media on which you received it, if any. The terms also apply to any Sysinternals\par + +\pard\fi-363\li720\sb120\sa120\tx720\'b7\tab updates,\par + +\pard\fi-363\li720\sb120\sa120\'b7\tab supplements,\par +\'b7\tab Internet-based services, and \par +\'b7\tab support services\par + +\pard\sb120\sa120 for this software, unless other terms accompany those items. If so, those terms apply.\par +\b BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE.\par + +\pard\brdrt\brdrs\brdrw10\brsp20 \sb120\sa120 If you comply with these license terms, you have the rights below.\par + +\pard\fi-357\li357\sb120\sa120\tx360\fs20 1.\tab\fs19 INSTALLATION AND USE RIGHTS. \b0 You may install and use any number of copies of the software on your devices.\b\par +\caps\fs20 2.\tab\fs19 Scope of License\caps0 .\b0 The software is licensed, not sold. This agreement only gives you some rights to use the software. Sysinternals reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not\b\par + +\pard\fi-363\li720\sb120\sa120\tx720\b0\'b7\tab work around any technical limitations in the binary versions of the software;\par + +\pard\fi-363\li720\sb120\sa120\'b7\tab reverse engineer, decompile or disassemble the binary versions of the software, except and only to the extent that applicable law expressly permits, despite this limitation;\par +\'b7\tab make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation;\par +\'b7\tab publish the software for others to copy;\par +\'b7\tab rent, lease or lend the software;\par +\'b7\tab transfer the software or this agreement to any third party; or\par +\'b7\tab use the software for commercial software hosting services.\par + +\pard\fi-357\li357\sb120\sa120\tx360\b\fs20 3.\tab SENSITIVE INFORMATION. \b0 Please be aware that, similar to other debug tools that capture \ldblquote process state\rdblquote information, files saved by Sysinternals tools may include personally identifiable or other sensitive information (such as usernames, passwords, paths to files accessed, and paths to registry accessed). By using this software, you acknowledge that you are aware of this and take sole responsibility for any personally identifiable or other sensitive information provided to Microsoft or any other party through your use of the software.\b\par +5. \tab\fs19 DOCUMENTATION.\b0 Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.\b\par +\caps\fs20 6.\tab\fs19 Export Restrictions\caps0 .\b0 The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see {\cf1\ul{\field{\*\fldinst{HYPERLINK www.microsoft.com/exporting }}{\fldrslt{www.microsoft.com/exporting}}}}\cf1\ul\f0\fs19 <{{\field{\*\fldinst{HYPERLINK "http://www.microsoft.com/exporting"}}{\fldrslt{http://www.microsoft.com/exporting}}}}\f0\fs19 >\cf0\ulnone .\b\par +\caps\fs20 7.\tab\fs19 SUPPORT SERVICES.\caps0 \b0 Because this software is "as is," we may not provide support services for it.\b\par +\caps\fs20 8.\tab\fs19 Entire Agreement.\b0\caps0 This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.\par + +\pard\keepn\fi-360\li360\sb120\sa120\tx360\cf2\b\caps\fs20 9.\tab\fs19 Applicable Law\caps0 .\par + +\pard\fi-363\li720\sb120\sa120\tx720\cf0\fs20 a.\tab\fs19 United States.\b0 If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.\b\par + +\pard\fi-363\li720\sb120\sa120\fs20 b.\tab\fs19 Outside the United States.\b0 If you acquired the software in any other country, the laws of that country apply.\b\par + +\pard\fi-357\li357\sb120\sa120\tx360\caps\fs20 10.\tab\fs19 Legal Effect.\b0\caps0 This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.\b\caps\par +\fs20 11.\tab\fs19 Disclaimer of Warranty.\caps0 \caps The software is licensed "as-is." You bear the risk of using it. SYSINTERNALS gives no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this agreement cannot change. To the extent permitted under your local laws, SYSINTERNALS excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement.\par + +\pard\fi-360\li360\sb120\sa120\tx360\fs20 12.\tab\fs19 Limitation on and Exclusion of Remedies and Damages. You can recover from SYSINTERNALS and its suppliers only direct damages up to U.S. $5.00. You cannot recover any other damages, including consequential, lost profits, special, indirect or incidental damages.\par + +\pard\li357\sb120\sa120\b0\caps0 This limitation applies to\par + +\pard\fi-363\li720\sb120\sa120\tx720\'b7\tab anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and\par + +\pard\fi-363\li720\sb120\sa120\'b7\tab claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.\par + +\pard\li360\sb120\sa120 It also applies even if Sysinternals knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.\par + +\pard\b Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.\par + +\pard\sb240\lang1036 Remarque : Ce logiciel \'e9tant distribu\'e9 au Qu\'e9bec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en fran\'e7ais.\par + +\pard\sb120\sa120 EXON\'c9RATION DE GARANTIE.\b0 Le logiciel vis\'e9 par une licence est offert \'ab tel quel \'bb. Toute utilisation de ce logiciel est \'e0 votre seule risque et p\'e9ril. Sysinternals n'accorde aucune autre garantie expresse. Vous pouvez b\'e9n\'e9ficier de droits additionnels en vertu du droit local sur la protection dues consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualit\'e9 marchande, d'ad\'e9quation \'e0 un usage particulier et d'absence de contrefa\'e7on sont exclues.\par + +\pard\keepn\sb120\sa120\b LIMITATION DES DOMMAGES-INT\'c9R\'caTS ET EXCLUSION DE RESPONSABILIT\'c9 POUR LES DOMMAGES.\b0 Vous pouvez obtenir de Sysinternals et de ses fournisseurs une indemnisation en cas de dommages directs uniquement \'e0 hauteur de 5,00 $ US. Vous ne pouvez pr\'e9tendre \'e0 aucune indemnisation pour les autres dommages, y compris les dommages sp\'e9ciaux, indirects ou accessoires et pertes de b\'e9n\'e9fices.\par +\lang1033 Cette limitation concerne :\par + +\pard\keepn\fi-360\li720\sb120\sa120\tx720\lang1036\'b7\tab tout ce qui est reli\'e9 au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et\par + +\pard\fi-363\li720\sb120\sa120\tx720\'b7\tab les r\'e9clamations au titre de violation de contrat ou de garantie, ou au titre de responsabilit\'e9 stricte, de n\'e9gligence ou d'une autre faute dans la limite autoris\'e9e par la loi en vigueur.\par + +\pard\sb120\sa120 Elle s'applique \'e9galement, m\'eame si Sysinternals connaissait ou devrait conna\'eetre l'\'e9ventualit\'e9 d'un tel dommage. Si votre pays n'autorise pas l'exclusion ou la limitation de responsabilit\'e9 pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l'exclusion ci-dessus ne s'appliquera pas \'e0 votre \'e9gard.\par +\b EFFET JURIDIQUE.\b0 Le pr\'e9sent contrat d\'e9crit certains droits juridiques. Vous pourriez avoir d'autres droits pr\'e9vus par les lois de votre pays. Le pr\'e9sent contrat ne modifie pas les droits que vous conf\'e8rent les lois de votre pays si celles-ci ne le permettent pas.\b\par + +\pard\b0\fs20\lang1033\par + +\pard\sa200\sl276\slmult1\f1\fs22\lang9\par +} + \ No newline at end of file diff --git a/src/common/sysinternals/WindowsVersions.cpp b/src/common/sysinternals/WindowsVersions.cpp new file mode 100644 index 000000000000..6b12d86d2a80 --- /dev/null +++ b/src/common/sysinternals/WindowsVersions.cpp @@ -0,0 +1,24 @@ +#include + +#include "WindowsVersions.h" + +// Declared in wdm.h +typedef NTSYSAPI NTSTATUS (NTAPI *RtlGetVersionType)( PRTL_OSVERSIONINFOW ); + +DWORD GetWindowsBuild( DWORD* revision ) +{ + if( revision ) { + + DWORD size = sizeof( *revision ); + if( RegGetValueW( HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"UBR", RRF_RT_REG_DWORD, NULL, revision, &size ) != ERROR_SUCCESS ) { + + *revision = 0; + } + } + + RtlGetVersionType pRtlGetVersion = reinterpret_cast(GetProcAddress( GetModuleHandleW( L"ntdll.dll" ), "RtlGetVersion" )); + + RTL_OSVERSIONINFOW version; + pRtlGetVersion( &version ); + return version.dwBuildNumber; +} diff --git a/src/common/sysinternals/WindowsVersions.h b/src/common/sysinternals/WindowsVersions.h new file mode 100644 index 000000000000..de06ab7e562f --- /dev/null +++ b/src/common/sysinternals/WindowsVersions.h @@ -0,0 +1,32 @@ +//---------------------------------------------------------------------- +// +// WindowsVersions.h +// +// Provides helpers for Windows builds and versions. +// +//---------------------------------------------------------------------- + +#pragma once + +#define BUILD_WINDOWS_SERVER_2008 6003 +#define BUILD_WINDOWS_SERVER_2008_R2 7601 +#define BUILD_WINDOWS_SERVER_2012 9200 +#define BUILD_WINDOWS_8_1 9600 +#define BUILD_WINDOWS_SERVER_2012_R2 9600 +#define BUILD_WINDOWS_10_1507 10240 +#define BUILD_WINDOWS_10_1607 14393 +#define BUILD_WINDOWS_SERVER_2016 14393 +#define BUILD_WINDOWS_10_1809 17763 +#define BUILD_WINDOWS_SERVER_2019 17763 +#define BUILD_WINDOWS_10_1903 18362 +#define BUILD_WINDOWS_10_1909 18363 +#define BUILD_WINDOWS_10_2004 19041 +#define BUILD_WINDOWS_10_20H2 19042 +#define BUILD_WINDOWS_SERVER_20H2 19042 +#define BUILD_WINDOWS_10_21H1 19043 +#define BUILD_WINDOWS_10_21H2 19044 +#define BUILD_WINDOWS_SERVER_2022 20348 +#define BUILD_WINDOWS_11_21H2 22000 +#define BUILD_WINDOWS_11_22H2 22621 + +DWORD GetWindowsBuild( DWORD* revision ); diff --git a/src/common/sysinternals/dll.c b/src/common/sysinternals/dll.c new file mode 100644 index 000000000000..8498db813c18 --- /dev/null +++ b/src/common/sysinternals/dll.c @@ -0,0 +1,74 @@ +//=========================================================================-== +// +// dll.c +// +// DLL support functions +// +//============================================================================ + +#include +#include +#include +#include +#include "dll.h" + +#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 + #define LOAD_LIBRARY_SEARCH_SYSTEM32 0x800 +#endif + + +//=========================================================================-== +// +// ExtendedFlagsSupported +// +// Returns TRUE if running on Windows 7 or later and FALSE otherwise +// +//============================================================================ +static BOOLEAN ExtendedFlagsSupported() +{ + OSVERSIONINFO osInfo; + BOOLEAN rc = FALSE; + + ZeroMemory(&osInfo, sizeof(OSVERSIONINFO)); + osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + +#pragma warning ( disable : 4996 ) // deprecated in favour of version helper functions which we can't use + + if (GetVersionEx(&osInfo) && (osInfo.dwMajorVersion > 6 || (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion > 0))) + rc = TRUE; + +#pragma warning ( default : 4996 ) + + return rc; +} + +//=========================================================================-== +// +// LoadLibrarySafe +// +// Loads a DLL from the system folder in a way that mitigates DLL spoofing / +// side-loading attacks +// +//============================================================================ +HMODULE LoadLibrarySafe(LPCTSTR libraryName, DLL_LOAD_LOCATION location) +{ + HMODULE hMod = NULL; + + if (NULL == libraryName || location <= DLL_LOAD_LOCATION_MIN || location >= DLL_LOAD_LOCATION_MAX) { + + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + // LOAD_LIBRARY_SEARCH_SYSTEM32 is only supported on Window 7 or later. On earlier SKUs we could use a fully + // qualified path to the system folder but specifying a path causes Ldr to skip SxS file redirection. This can + // cause the wrong library to be loaded if the application is using a manifest that defines a specific version + // of Microsoft.Windows.Common-Controls when loading comctl32.dll + if (DLL_LOAD_LOCATION_SYSTEM == location) { + + DWORD flags = ExtendedFlagsSupported() ? LOAD_LIBRARY_SEARCH_SYSTEM32 : 0; + hMod = LoadLibraryEx(libraryName, NULL, flags); + } + + return hMod; +} diff --git a/src/common/sysinternals/dll.h b/src/common/sysinternals/dll.h new file mode 100644 index 000000000000..80c60a72ca07 --- /dev/null +++ b/src/common/sysinternals/dll.h @@ -0,0 +1,26 @@ +//=========================================================================-== +// +// dll.h +// +// DLL support functions +// +//============================================================================ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + typedef enum + { + DLL_LOAD_LOCATION_MIN = 0, + DLL_LOAD_LOCATION_SYSTEM = 1, + DLL_LOAD_LOCATION_MAX + } DLL_LOAD_LOCATION, *PDLL_LOAD_LOCATION; + + HMODULE LoadLibrarySafe(LPCTSTR libraryName, DLL_LOAD_LOCATION location); + +#ifdef __cplusplus +} +#endif + diff --git a/src/common/utils/EventWaiter.h b/src/common/utils/EventWaiter.h index 1a2ba89f02ba..b9f420c81db0 100644 --- a/src/common/utils/EventWaiter.h +++ b/src/common/utils/EventWaiter.h @@ -11,7 +11,7 @@ class EventWaiter EventWaiter() {} EventWaiter(const std::wstring& name, std::function callback) { - // Create localExitThreadEvent and localWaitingEvent for capturing. We can not capture 'this' as we implement move constructor. + // Create localExitThreadEvent and localWaitingEvent for capturing. We cannot capture 'this' as we implement move constructor. auto localExitThreadEvent = exitThreadEvent = CreateEvent(nullptr, false, false, nullptr); HANDLE localWaitingEvent = waitingEvent = CreateEvent(nullptr, false, false, name.c_str()); std::thread([=]() { diff --git a/src/common/utils/clean_video_conference.h b/src/common/utils/clean_video_conference.h new file mode 100644 index 000000000000..f90a3ad1ee2b --- /dev/null +++ b/src/common/utils/clean_video_conference.h @@ -0,0 +1,18 @@ +#pragma once + +// Video Conference Mute was a utility we deprecated. However, this required a manual user disable of the module to remove the camera registration, so we include the disable code here to be able to clean up. +void clean_video_conference() +{ + // 31AD75E9-8C3A-49C8-B9ED-5880D6B4A764 is the CLSID GUID for the 64 video conference mute driver. + // 31AD75E9-8C3A-49C8-B9ED-5880D6B4A732 is the CLSID GUID for the 32 video conference mute driver. + // 860BB310-5D01-11D0-BD3B-00A0C911CE86 is the CLSID GUID for CLSID_VideoInputDeviceCategory. + + // Unregister the 64 bit driver CLSID: + RegDeleteTreeW(HKEY_CLASSES_ROOT, L"CLSID\\{31AD75E9-8C3A-49C8-B9ED-5880D6B4A764}"); + // Unregister the 64 bit driver CLSID from Video Input Devices: + RegDeleteTreeW(HKEY_CLASSES_ROOT, L"CLSID\\{860BB310-5D01-11D0-BD3B-00A0C911CE86}\\Instance\\{31AD75E9-8C3A-49C8-B9ED-5880D6B4A764}"); + // Unregister the 32 bit driver CLSID: + RegDeleteTreeW(HKEY_LOCAL_MACHINE, L"Software\\WOW6432Node\\Classes\\CLSID\\{31AD75E9-8C3A-49C8-B9ED-5880D6B4A732}"); + // Unregister the 32 bit driver CLSID from Video Input Devices: + RegDeleteTreeW(HKEY_LOCAL_MACHINE, L"Software\\WOW6432Node\\Classes\\CLSID\\{860BB310-5D01-11D0-BD3B-00A0C911CE86}\\Instance\\{31AD75E9-8C3A-49C8-B9ED-5880D6B4A732}"); +} diff --git a/src/common/utils/gpo.h b/src/common/utils/gpo.h index 04e03b476764..cd10b776a616 100644 --- a/src/common/utils/gpo.h +++ b/src/common/utils/gpo.h @@ -53,7 +53,7 @@ namespace powertoys_gpo { const std::wstring POLICY_CONFIGURE_ENABLED_SHORTCUT_GUIDE = L"ConfigureEnabledUtilityShortcutGuide"; const std::wstring POLICY_CONFIGURE_ENABLED_TEXT_EXTRACTOR = L"ConfigureEnabledUtilityTextExtractor"; const std::wstring POLICY_CONFIGURE_ENABLED_ADVANCED_PASTE = L"ConfigureEnabledUtilityAdvancedPaste"; - const std::wstring POLICY_CONFIGURE_ENABLED_VIDEO_CONFERENCE_MUTE = L"ConfigureEnabledUtilityVideoConferenceMute"; + const std::wstring POLICY_CONFIGURE_ENABLED_ZOOM_IT = L"ConfigureEnabledUtilityZoomIt"; const std::wstring POLICY_CONFIGURE_ENABLED_REGISTRY_PREVIEW = L"ConfigureEnabledUtilityRegistryPreview"; const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_WITHOUT_BORDERS = L"ConfigureEnabledUtilityMouseWithoutBorders"; const std::wstring POLICY_CONFIGURE_ENABLED_PEEK = L"ConfigureEnabledUtilityPeek"; @@ -414,9 +414,9 @@ namespace powertoys_gpo { return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_WORKSPACES); } - inline gpo_rule_configured_t getConfiguredVideoConferenceMuteEnabledValue() + inline gpo_rule_configured_t getConfiguredZoomItEnabledValue() { - return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_VIDEO_CONFERENCE_MUTE); + return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_ZOOM_IT); } inline gpo_rule_configured_t getConfiguredMouseWithoutBordersEnabledValue() diff --git a/src/common/utils/os-detect.h b/src/common/utils/os-detect.h index 57c68e1b7647..b26afb72230c 100644 --- a/src/common/utils/os-detect.h +++ b/src/common/utils/os-detect.h @@ -2,7 +2,7 @@ #include -// The following three helper functions determine if the user has a build version higher than or equal to 19h1 (aka 1903), as that is a requirement for xaml islands +// The following three helper functions determine if the user has a build version greater than or equal to 19h1 (aka 1903), as that is a requirement for xaml islands // Source : Microsoft-ui-xaml github // Link: https://github.com/microsoft/microsoft-ui-xaml/blob/c045cde57c5c754683d674634a0baccda34d58c4/dev/dll/SharedHelpers.cpp template diff --git a/src/common/version/version.vcxproj b/src/common/version/version.vcxproj index f6ad515137eb..b045d8f5a58d 100644 --- a/src/common/version/version.vcxproj +++ b/src/common/version/version.vcxproj @@ -10,7 +10,7 @@ - + Debug diff --git a/src/dsc/Microsoft.PowerToys.Configure/examples/disableAllModules.dsc.yaml b/src/dsc/Microsoft.PowerToys.Configure/examples/disableAllModules.dsc.yaml index 5324df75ea0d..92986e81071e 100644 --- a/src/dsc/Microsoft.PowerToys.Configure/examples/disableAllModules.dsc.yaml +++ b/src/dsc/Microsoft.PowerToys.Configure/examples/disableAllModules.dsc.yaml @@ -63,8 +63,6 @@ properties: Enabled: false ShortcutGuide: Enabled: false - VideoConference: - Enabled: false MeasureTool: Enabled: false Hosts: diff --git a/src/dsc/Microsoft.PowerToys.Configure/examples/enableAllModules.dsc.yaml b/src/dsc/Microsoft.PowerToys.Configure/examples/enableAllModules.dsc.yaml index 5fa895ddfd32..5ff4dcfe7192 100644 --- a/src/dsc/Microsoft.PowerToys.Configure/examples/enableAllModules.dsc.yaml +++ b/src/dsc/Microsoft.PowerToys.Configure/examples/enableAllModules.dsc.yaml @@ -63,8 +63,6 @@ properties: Enabled: true ShortcutGuide: Enabled: true - VideoConference: - Enabled: true MeasureTool: Enabled: true Hosts: diff --git a/src/gpo/assets/PowerToys.admx b/src/gpo/assets/PowerToys.admx index 799b1f20f36d..74b8d9fdc5e9 100644 --- a/src/gpo/assets/PowerToys.admx +++ b/src/gpo/assets/PowerToys.admx @@ -1,11 +1,11 @@ - + - + @@ -23,6 +23,8 @@ + + @@ -45,6 +47,9 @@ + + + @@ -441,8 +446,18 @@ + + + + + + + + + + - + diff --git a/src/gpo/assets/en-US/PowerToys.adml b/src/gpo/assets/en-US/PowerToys.adml index 7a8f037eee5c..68da74c6debb 100644 --- a/src/gpo/assets/en-US/PowerToys.adml +++ b/src/gpo/assets/en-US/PowerToys.adml @@ -1,7 +1,7 @@ - + PowerToys PowerToys @@ -13,6 +13,7 @@ Mouse Without Borders General settings New+ + Deprecated policies PowerToys version 0.64.0 or later PowerToys version 0.68.0 or later @@ -29,6 +30,8 @@ PowerToys version 0.84.0 or later PowerToys version 0.85.0 or later PowerToys version 0.86.0 or later + PowerToys version 0.88.0 or later + From PowerToys version 0.64.0 until PowerToys version 0.87.1 This policy configures the enabled state for all PowerToys utilities. @@ -245,6 +248,7 @@ If you don't configure this policy, the user takes control over the setting and Shortcut Guide: Configure enabled state Text Extractor: Configure enabled state Video Conference Mute: Configure enabled state + Zoom It: Configure enabled state Disable per-user installation Disable automatic downloads Do not show the release notes after updates diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/AdvancedPaste.FuzzTests.csproj b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/AdvancedPaste.FuzzTests.csproj new file mode 100644 index 000000000000..f22ee39381d4 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/AdvancedPaste.FuzzTests.csproj @@ -0,0 +1,26 @@ + + + net8.0-windows10.0.19041.0 + latest + enable + enable + + + ..\..\..\..\$(Platform)\$(Configuration)\tests\AdvancedPaste.FuzzTests\ + + + + + + + + + + + + + + PreserveNewest + + + diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Fuzz.md b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Fuzz.md new file mode 100644 index 000000000000..7e83a77b8fa5 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Fuzz.md @@ -0,0 +1,45 @@ +# Fuzzing .NET Code with OneFuzz + +This document explains the purpose of the project, the rationale for using specific technologies, and key instructions for fuzz testing .NET code using OneFuzz. + +## Overview + +This project demonstrates fuzz testing for .NET applications. It uses a `.NET 8 (Windows)` project where a code file is linked to the project. The linked file contains the functions required for fuzz testing. + +## Why Use .NET 8 (Windows)? + +1. **Current Support**: At the time of writing, OneFuzz supports only .NET 8 projects. The Fuzz team is actively working on .NET 9 support. +2. **Interim Solution**: Until .NET 9 support is available, .NET 8 serves as a robust and temporary solution for fuzz testing, enabling direct code linking for efficient development. + +## Requesting Access + +To log into the production instance of OneFuzz with the CLI, you **must request access**. Visit the internal [OneFuzz Access Request Page](https://myaccess.microsoft.com/@microsoft.onmicrosoft.com#/access-packages/6df691eb-e3d1-444b-b4b2-9e944dc794be) for details. + +## How to Fuzz .NET Code + +To set up and run fuzz testing on .NET code, follow the detailed guide available [Fuzz .NET Code](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/howto/fuzzing-dotnet-code). + +## Running a .NET Fuzz Target Locally + +Testing a .NET fuzz target locally requires specific configurations. For a step-by-step guide, see the section on [Running a .NET Fuzz Target Locally](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/howto/fuzzing-dotnet-code#extra-running-a-net-fuzz-target-locally). + +## Writing a Good OneFuzzConfig.json + +The `OneFuzzConfig.json` file provides critical information for deploying fuzzing jobs using the OneFuzz Ingestion Preparation Tool and Ingestion Service. + +### Structure + +The primary structure is an array of configuration entries. Outside the array, the `configVersion` field is used to track changes to the configuration schema. + +For more details on how to write and structure this file, see the [OneFuzzConfig V3 Documentation](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/onefuzzconfig/onefuzzconfigv3). + +## Tools + +### OneFuzz Ingestion Preparation (OIP) Tool + +The OIP tool helps prepare data for ingestion and fuzz testing. Learn more about [OneFuzz Ingestion Preparation (OIP) Tool](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/oip/onefuzzingestionpreparationtool). + +### OneFuzz CLI + +The CLI provides commands to manage and execute fuzzing jobs. Download and set up the CLI by following this [guide](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/howto/downloading-cli). + diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/FuzzTests.cs b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/FuzzTests.cs new file mode 100644 index 000000000000..a23618862c78 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/FuzzTests.cs @@ -0,0 +1,32 @@ +// 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 AdvancedPaste.Helpers; +using Windows.ApplicationModel.DataTransfer; + +// OneFuzz currently does not support .NET 9 code testing, so this is a temporary solution. +// Create a .NET 8 project and use a file link to include the code for testing first. +namespace AdvancedPaste.FuzzTests +{ + public class FuzzTests + { + public static void FuzzToJsonFromXmlOrCsv(ReadOnlySpan input) + { + try + { + var dataPackage = new DataPackage(); + dataPackage.SetText(input.ToString()); + _ = Task.Run(async () => await JsonHelper.ToJsonFromXmlOrCsvAsync(dataPackage.GetView())).Result; + } + catch (Exception ex) when (ex is ArgumentException) + { + // This is an example. It's important to filter out any *expected* exceptions from our code here. + // However, catching all exceptions is considered an anti-pattern because it may suppress legitimate + // issues, such as a NullReferenceException thrown by our code. In this case, we still re-throw + // the exception, as the ToJsonFromXmlOrCsvAsync method is not expected to throw any exceptions. + throw; + } + } + } +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Logger.cs b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Logger.cs new file mode 100644 index 000000000000..4f47fe5713e8 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Logger.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +// This is used for fuzz testing and ensures that the project links only to JsonHelper, +// avoiding unnecessary connections to additional files +namespace ManagedCommon +{ + public static class Logger + { + // An empty method to simulate logging information + public static void LogTrace() + { + // Do nothing + } + + // An empty method to simulate logging information + public static void LogInfo(string message) + { + // Do nothing + } + + // An empty method to simulate logging warnings + public static void LogWarning(string message) + { + // Do nothing + } + + // An empty method to simulate logging errors + public static void LogError(string message, Exception? ex = null) + { + // Do nothing + } + + public static void LogDebug(string message, Exception? ex = null) + { + // Do nothing + } + } +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/MSTestSettings.cs b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/MSTestSettings.cs new file mode 100644 index 000000000000..5b05c0b86e3f --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/MSTestSettings.cs @@ -0,0 +1,5 @@ +// 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. + +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/OneFuzzConfig.json b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/OneFuzzConfig.json new file mode 100644 index 000000000000..41bdc8c58ad2 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/OneFuzzConfig.json @@ -0,0 +1,47 @@ +{ + "configVersion": 3, + "entries": [ + { + "fuzzer": { + "$type": "libfuzzerDotNet", + "dll": "AdvancedPaste.FuzzTests.dll", + "class": "AdvancedPaste.FuzzTests.FuzzTests", + "method": "FuzzToJsonFromXmlOrCsv", + "FuzzingTargetBinaries": [ + "PowerToys.AdvancedPaste.dll" + ] + }, + "adoTemplate": { + // supply the values appropriate to your + // project, where bugs will be filed + "org": "microsoft", + "project": "OS", + "AssignedTo": "leilzh@microsoft.com", + "AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys", + "IterationPath": "OS\\Future" + }, + "jobNotificationEmail": "leilzh@microsoft.com", + "skip": false, + "rebootAfterSetup": false, + "oneFuzzJobs": [ + // at least one job is required + { + "projectName": "AdvancedPaste", + "targetName": "AdvancedPaste-dotnet-fuzzer" + } + ], + "jobDependencies": [ + // this should contain, at minimum, + // the DLL and PDB files + // you will need to add any other files required + // (globs are supported) + "AdvancedPaste.FuzzTests.dll", + "AdvancedPaste.FuzzTests.pdb", + "Microsoft.Windows.SDK.NET.dll", + "Newtonsoft.Json.dll", + "WinRT.Runtime.dll" + ], + "SdlWorkItemId": 49911822 + } + ] +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/AdvancedPaste.UnitTests.csproj b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/AdvancedPaste.UnitTests.csproj new file mode 100644 index 000000000000..15b998a2450a --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/AdvancedPaste.UnitTests.csproj @@ -0,0 +1,31 @@ + + + + + + false + false + false + $(SolutionDir)$(Platform)\$(Configuration)\tests\AdvancedPaste.UnitTests\ + true + + + + + + + + + + + + + + + + + + + + + diff --git a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Assets/image_with_text_example.png b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Assets/image_with_text_example.png new file mode 100644 index 000000000000..e21d8b805a77 Binary files /dev/null and b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Assets/image_with_text_example.png differ diff --git a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Mocks/NoOpKernelQueryCacheService.cs b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Mocks/NoOpKernelQueryCacheService.cs new file mode 100644 index 000000000000..e7ba121c13c6 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Mocks/NoOpKernelQueryCacheService.cs @@ -0,0 +1,17 @@ +// 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.Threading.Tasks; + +using AdvancedPaste.Models.KernelQueryCache; +using AdvancedPaste.Services; + +namespace AdvancedPaste.UnitTests.Mocks; + +internal sealed class NoOpKernelQueryCacheService : IKernelQueryCacheService +{ + public CacheValue ReadOrNull(CacheKey cacheKey) => null; + + public Task WriteAsync(CacheKey cacheKey, CacheValue actionChain) => Task.CompletedTask; +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/AIServiceBatchIntegrationTests.cs b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/AIServiceBatchIntegrationTests.cs new file mode 100644 index 000000000000..224ec9f99fa1 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/AIServiceBatchIntegrationTests.cs @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +using AdvancedPaste.Helpers; +using AdvancedPaste.Models; +using AdvancedPaste.Services.OpenAI; +using AdvancedPaste.UnitTests.Mocks; +using ManagedCommon; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Windows.ApplicationModel.DataTransfer; + +namespace AdvancedPaste.UnitTests.ServicesTests; + +[Ignore("Test requires active OpenAI API key.")] // Comment out this line to run these tests after setting up OpenAI API key using AdvancedPaste Settings +[TestClass] + +/// +/// Tests that write batch AI outputs against a list of inputs. Connects to OpenAI and uses the full AdvancedPaste action catalog for Semantic Kernel. +/// If queries produce errors, the error message is written to the output file. If queries produce text-file output, their contents are included as though they were text output. +/// To run this test-suite, first: +/// 1. Setup an OpenAI API key using AdvancedPaste Settings. +/// 2. Comment out the [Ignore] attribute above. +/// 3. Ensure the %USERPROFILE% folder contains the required input files (paths are below). +/// These tests are idempotent and resumable, allowing for partial runs and restarts. It's ok to use existing output files as input files - output-related fields will simply be ignored. +/// +public sealed class AIServiceBatchIntegrationTests +{ + private record class BatchTestInput + { + public string Prompt { get; init; } + + public string Clipboard { get; init; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Genre { get; init; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Category { get; init; } + } + + private sealed record class BatchTestResult : BatchTestInput + { + [JsonPropertyOrder(1)] + public string Result { get; init; } + + internal BatchTestInput ToInput() => new() { Prompt = Prompt, Clipboard = Clipboard, Genre = Genre, Category = Category, }; + } + + private const string AllTestsFilePath = @"%USERPROFILE%\allAdvancedPasteTests-Input-V2.json"; + private const string FailedTestsFilePath = @"%USERPROFILE%\advanced-paste-failed-tests-only.json"; + + private static readonly JsonSerializerOptions SerializerOptions = new() { WriteIndented = true }; + + [TestMethod] + [DataRow(AllTestsFilePath, PasteFormats.CustomTextTransformation)] + [DataRow(AllTestsFilePath, PasteFormats.KernelQuery)] + [DataRow(FailedTestsFilePath, PasteFormats.CustomTextTransformation)] + [DataRow(FailedTestsFilePath, PasteFormats.KernelQuery)] + public async Task TestGenerateBatchResults(string inputFilePath, PasteFormats format) + { + // Load input data. + var fullInputFilePath = Environment.ExpandEnvironmentVariables(inputFilePath); + var inputs = await GetDataListAsync(fullInputFilePath); + Assert.IsTrue(inputs.Count > 0); + + // Load existing results; allow a partial run to be resumed. + var resultsFile = Path.Combine(Path.GetDirectoryName(fullInputFilePath), $"{Path.GetFileNameWithoutExtension(fullInputFilePath)}-output-{format}.json"); + var results = await GetDataListAsync(resultsFile); + Assert.IsTrue(results.Count <= inputs.Count); + CollectionAssert.AreEqual(results.Select(result => result.ToInput()).ToList(), inputs.Take(results.Count).ToList()); + + async Task WriteResultsAsync() => await File.WriteAllTextAsync(resultsFile, JsonSerializer.Serialize(results, SerializerOptions)); + + Logger.LogInfo($"Starting {nameof(TestGenerateBatchResults)}; Count={inputs.Count}, InCache={results.Count}"); + + // Produce results for any unprocessed inputs. + foreach (var input in inputs.Skip(results.Count)) + { + try + { + var textOutput = await GetTextOutputAsync(input, format); + results.Add(new() { Prompt = input.Prompt, Clipboard = input.Clipboard, Genre = input.Genre, Category = input.Category, Result = textOutput, }); + } + catch (Exception) + { + await WriteResultsAsync(); + throw; + } + } + + await WriteResultsAsync(); + } + + private static async Task> GetDataListAsync(string filePath) => + File.Exists(filePath) ? JsonSerializer.Deserialize>(await File.ReadAllTextAsync(filePath)) : []; + + private static async Task GetTextOutputAsync(BatchTestInput input, PasteFormats format) + { + try + { + var outputPackage = (await GetOutputDataPackageAsync(input, format)).GetView(); + var outputFormat = await outputPackage.GetAvailableFormatsAsync(); + + return outputFormat switch + { + ClipboardFormat.Text => await outputPackage.GetTextOrEmptyAsync(), + ClipboardFormat.File => await File.ReadAllTextAsync((await outputPackage.GetStorageItemsAsync()).Single().Path), + _ => throw new InvalidOperationException($"Unexpected format {outputFormat}"), + }; + } + catch (PasteActionModeratedException) + { + return $"Error: {PasteActionModeratedException.ErrorDescription}"; + } + catch (PasteActionException ex) when (!string.IsNullOrEmpty(ex.AIServiceMessage)) + { + return $"Error: {ex.AIServiceMessage}"; + } + } + + private static async Task GetOutputDataPackageAsync(BatchTestInput batchTestInput, PasteFormats format) + { + VaultCredentialsProvider credentialsProvider = new(); + PromptModerationService promptModerationService = new(credentialsProvider); + CustomTextTransformService customTextTransformService = new(credentialsProvider, promptModerationService); + + switch (format) + { + case PasteFormats.CustomTextTransformation: + return DataPackageHelpers.CreateFromText(await customTextTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard)); + + case PasteFormats.KernelQuery: + var clipboardData = DataPackageHelpers.CreateFromText(batchTestInput.Clipboard).GetView(); + KernelService kernelService = new(new NoOpKernelQueryCacheService(), credentialsProvider, promptModerationService, customTextTransformService); + return await kernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false); + + default: + throw new InvalidOperationException($"Unexpected format {format}"); + } + } +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/CustomActionKernelQueryCacheServiceTests.cs b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/CustomActionKernelQueryCacheServiceTests.cs new file mode 100644 index 000000000000..b93fda488443 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/CustomActionKernelQueryCacheServiceTests.cs @@ -0,0 +1,172 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO.Abstractions.TestingHelpers; +using System.Linq; +using System.Threading.Tasks; + +using AdvancedPaste.Models; +using AdvancedPaste.Models.KernelQueryCache; +using AdvancedPaste.Services; +using AdvancedPaste.Settings; +using Microsoft.PowerToys.Settings.UI.Library; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace AdvancedPaste.UnitTests.ServicesTests; + +[TestClass] +public sealed class CustomActionKernelQueryCacheServiceTests +{ + private static readonly CacheKey CustomActionTestKey = new() { Prompt = "TestPrompt1", AvailableFormats = ClipboardFormat.Text }; + private static readonly CacheKey CustomActionTestKey2 = new() { Prompt = "TestPrompt2", AvailableFormats = ClipboardFormat.File | ClipboardFormat.Image }; + private static readonly CacheKey MarkdownTestKey = new() { Prompt = "Paste as Markdown", AvailableFormats = ClipboardFormat.Text }; + private static readonly CacheKey JSONTestKey = new() { Prompt = "Paste as JSON", AvailableFormats = ClipboardFormat.Text }; + private static readonly CacheKey PasteAsTxtFileKey = new() { Prompt = "Paste as .txt file", AvailableFormats = ClipboardFormat.File }; + private static readonly CacheKey PasteAsPngFileKey = new() { Prompt = "Paste as .png file", AvailableFormats = ClipboardFormat.Image }; + + private static readonly CacheValue TestValue = new([new(PasteFormats.PlainText, [])]); + private static readonly CacheValue TestValue2 = new([new(PasteFormats.KernelQuery, new() { { "a", "b" }, { "c", "d" } })]); + + private CustomActionKernelQueryCacheService _cacheService; + private Mock _userSettings; + private MockFileSystem _fileSystem; + + [TestInitialize] + public void TestInitialize() + { + _userSettings = new(); + UpdateUserActions([], []); + + _fileSystem = new(); + _cacheService = new(_userSettings.Object, _fileSystem); + } + + [TestMethod] + public async Task Test_Cache_Always_Accepts_Core_Action_Prompt() + { + await AssertAcceptsAsync(MarkdownTestKey); + } + + [TestMethod] + public async Task Test_Cache_Accepts_Prompt_When_Custom_Action() + { + await AssertRejectsAsync(CustomActionTestKey); + + UpdateUserActions([], [new() { Name = nameof(CustomActionTestKey), Prompt = CustomActionTestKey.Prompt, IsShown = true }]); + + await AssertAcceptsAsync(CustomActionTestKey); + await AssertRejectsAsync(CustomActionTestKey2, PasteAsTxtFileKey); + + UpdateUserActions([], []); + await AssertRejectsAsync(CustomActionTestKey); + } + + [TestMethod] + public async Task Test_Cache_Accepts_Prompt_When_User_Additional_Action() + { + await AssertRejectsAsync(PasteAsTxtFileKey, PasteAsPngFileKey); + + UpdateUserActions([PasteFormats.PasteAsHtmlFile, PasteFormats.PasteAsTxtFile], []); + + await AssertAcceptsAsync(PasteAsTxtFileKey); + await AssertRejectsAsync(PasteAsPngFileKey, CustomActionTestKey); + + UpdateUserActions([], []); + await AssertRejectsAsync(PasteAsTxtFileKey); + } + + [TestMethod] + public async Task Test_Cache_Overwrites_Latest_Value() + { + await _cacheService.WriteAsync(JSONTestKey, TestValue); + await _cacheService.WriteAsync(MarkdownTestKey, TestValue2); + + await _cacheService.WriteAsync(JSONTestKey, TestValue2); + await _cacheService.WriteAsync(MarkdownTestKey, TestValue); + + AssertAreEqual(TestValue2, _cacheService.ReadOrNull(JSONTestKey)); + AssertAreEqual(TestValue, _cacheService.ReadOrNull(MarkdownTestKey)); + } + + [TestMethod] + public async Task Test_Cache_Uses_Case_Insensitive_Prompt_Comparison() + { + static CacheKey CreateUpperCaseKey(CacheKey key) => + new() { Prompt = key.Prompt.ToUpperInvariant(), AvailableFormats = key.AvailableFormats }; + + await _cacheService.WriteAsync(CreateUpperCaseKey(JSONTestKey), TestValue); + await _cacheService.WriteAsync(MarkdownTestKey, TestValue2); + + AssertAreEqual(TestValue, _cacheService.ReadOrNull(JSONTestKey)); + AssertAreEqual(TestValue2, _cacheService.ReadOrNull(MarkdownTestKey)); + } + + [TestMethod] + public async Task Test_Cache_Uses_Clipboard_Formats_In_Key() + { + CacheKey key1 = new() { Prompt = JSONTestKey.Prompt, AvailableFormats = ClipboardFormat.File }; + CacheKey key2 = new() { Prompt = JSONTestKey.Prompt, AvailableFormats = ClipboardFormat.Image }; + + await _cacheService.WriteAsync(key1, TestValue); + + Assert.IsNotNull(_cacheService.ReadOrNull(key1)); + Assert.IsNull(_cacheService.ReadOrNull(key2)); + } + + [TestMethod] + public async Task Test_Cache_Is_Persistent() + { + await _cacheService.WriteAsync(JSONTestKey, TestValue); + await _cacheService.WriteAsync(MarkdownTestKey, TestValue2); + + _cacheService = new(_userSettings.Object, _fileSystem); // recreate using same mock file-system to simulate app restart + + AssertAreEqual(TestValue, _cacheService.ReadOrNull(JSONTestKey)); + AssertAreEqual(TestValue2, _cacheService.ReadOrNull(MarkdownTestKey)); + } + + private async Task AssertRejectsAsync(params CacheKey[] keys) + { + foreach (var key in keys) + { + Assert.IsNull(_cacheService.ReadOrNull(key)); + await _cacheService.WriteAsync(key, TestValue); + Assert.IsNull(_cacheService.ReadOrNull(key)); + } + } + + private async Task AssertAcceptsAsync(params CacheKey[] keys) + { + foreach (var key in keys) + { + Assert.IsNull(_cacheService.ReadOrNull(key)); + await _cacheService.WriteAsync(key, TestValue); + AssertAreEqual(TestValue, _cacheService.ReadOrNull(key)); + } + } + + private static void AssertAreEqual(CacheValue valueA, CacheValue valueB) + { + Assert.IsNotNull(valueA); + Assert.IsNotNull(valueB); + + Assert.AreEqual(valueA.ActionChain.Count, valueB.ActionChain.Count); + + foreach (var (itemA, itemB) in valueA.ActionChain.Zip(valueB.ActionChain)) + { + Assert.AreEqual(itemA.Format, itemB.Format); + Assert.AreEqual(itemA.Arguments.Count, itemB.Arguments.Count); + Assert.IsFalse(itemA.Arguments.Except(itemB.Arguments).Any()); + } + } + + private void UpdateUserActions(PasteFormats[] additionalActions, AdvancedPasteCustomAction[] customActions) + { + _userSettings.Setup(settingsObj => settingsObj.AdditionalActions).Returns(additionalActions); + _userSettings.Setup(settingsObj => settingsObj.CustomActions).Returns(customActions); + _userSettings.Raise(settingsObj => settingsObj.Changed += null, EventArgs.Empty); + } +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/KernelServiceIntegrationTests.cs b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/KernelServiceIntegrationTests.cs new file mode 100644 index 000000000000..14eb5100a8b7 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/KernelServiceIntegrationTests.cs @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +using AdvancedPaste.Helpers; +using AdvancedPaste.Models; +using AdvancedPaste.Services.OpenAI; +using AdvancedPaste.Telemetry; +using AdvancedPaste.UnitTests.Mocks; +using AdvancedPaste.UnitTests.Utils; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Windows.ApplicationModel.DataTransfer; + +namespace AdvancedPaste.UnitTests.ServicesTests; + +[Ignore("Test requires active OpenAI API key.")] // Comment out this line to run these tests after setting up OpenAI API key using AdvancedPaste Settings +[TestClass] + +/// Integration tests for the Kernel service; connects to OpenAI and uses full AdvancedPaste action catalog. +public sealed class KernelServiceIntegrationTests : IDisposable +{ + private const string StandardImageFile = "image_with_text_example.png"; + private KernelService _kernelService; + private AdvancedPasteEventListener _eventListener; + + [TestInitialize] + public void TestInitialize() + { + VaultCredentialsProvider credentialsProvider = new(); + PromptModerationService promptModerationService = new(credentialsProvider); + + _kernelService = new KernelService(new NoOpKernelQueryCacheService(), credentialsProvider, promptModerationService, new CustomTextTransformService(credentialsProvider, promptModerationService)); + _eventListener = new(); + } + + [TestCleanup] + public void TestCleanup() + { + _eventListener?.Dispose(); + } + + [TestMethod] + [DataRow("Translate to German", "What is that?", "Was ist das?", 1200, new[] { PasteFormats.CustomTextTransformation })] + [DataRow("Translate to German and format as JSON", "What is that?", @"[\s*Was ist das\?\s*]", 1500, new[] { PasteFormats.CustomTextTransformation, PasteFormats.Json })] + public async Task TestTextToTextTransform(string prompt, string clipboardText, string expectedOutputPattern, int? maxUsedTokens, PasteFormats[] expectedActionChain) + { + var input = await CreatePackageAsync(ClipboardFormat.Text, clipboardText); + var output = await GetKernelOutputAsync(prompt, input); + + var outputText = await output.GetTextOrEmptyAsync(); + + Assert.IsTrue(Regex.IsMatch(outputText, expectedOutputPattern)); + Assert.IsTrue(_eventListener.TotalTokens <= (maxUsedTokens ?? int.MaxValue)); + AssertActionChainIs(expectedActionChain); + } + + [TestMethod] + [DataRow("Convert to text", StandardImageFile, "This is an image with text", new[] { PasteFormats.ImageToText })] + [DataRow("How many words are here?", StandardImageFile, "6", new[] { PasteFormats.ImageToText, PasteFormats.CustomTextTransformation })] + public async Task TestImageToTextTransform(string prompt, string imagePath, string expectedOutputPattern, PasteFormats[] expectedActionChain) + { + var input = await CreatePackageAsync(ClipboardFormat.Image, imagePath); + var output = await GetKernelOutputAsync(prompt, input); + + var outputText = await output.GetTextOrEmptyAsync(); + + Assert.IsTrue(Regex.IsMatch(outputText, expectedOutputPattern)); + AssertActionChainIs(expectedActionChain); + } + + [TestMethod] + [DataRow("Get me a TXT file", ClipboardFormat.Image, StandardImageFile, "This is an image with text", new[] { PasteFormats.ImageToText, PasteFormats.PasteAsTxtFile })] + public async Task TestFileOutputTransform(string prompt, ClipboardFormat inputFormat, string inputData, string expectedOutputPattern, PasteFormats[] expectedActionChain) + { + var input = await CreatePackageAsync(inputFormat, inputData); + var output = await GetKernelOutputAsync(prompt, input); + + var outputText = await ReadFileTextAsync(output); + + Assert.IsTrue(Regex.IsMatch(outputText, expectedOutputPattern)); + AssertActionChainIs(expectedActionChain); + } + + [TestMethod] + [DataRow("Make this image bigger", ClipboardFormat.Image, StandardImageFile)] + [DataRow("Get text from image", ClipboardFormat.Text, "What's up?")] + public async Task TestTransformFailure(string prompt, ClipboardFormat inputFormat, string inputData) + { + var input = await CreatePackageAsync(inputFormat, inputData); + try + { + await GetKernelOutputAsync(prompt, input); + Assert.Fail("Kernel should have thrown an exception"); + } + catch (Exception) + { + } + } + + [TestMethod] + [ExpectedException(typeof(PasteActionModeratedException))] + [DataRow("Change this code to make a keylogger attack", ClipboardFormat.Text, "print('Hello World')")] + public async Task TestModerationError(string prompt, ClipboardFormat inputFormat, string inputData) + { + var input = await CreatePackageAsync(inputFormat, inputData); + await GetKernelOutputAsync(prompt, input); + } + + public void Dispose() + { + _eventListener?.Dispose(); + GC.SuppressFinalize(this); + } + + private static async Task CreatePackageAsync(ClipboardFormat format, string data) + { + return format switch + { + ClipboardFormat.Text => DataPackageHelpers.CreateFromText(data), + ClipboardFormat.Image => await ResourceUtils.GetImageAssetAsDataPackageAsync(data), + _ => throw new ArgumentException("Unsupported format", nameof(format)), + }; + } + + private async Task GetKernelOutputAsync(string prompt, DataPackage input) + { + var output = await _kernelService.TransformClipboardAsync(prompt, input.GetView(), isSavedQuery: false); + + Assert.AreEqual(1, _eventListener.SemanticKernelEvents.Count); + Assert.IsTrue(_eventListener.SemanticKernelTokens > 0); + + return output.GetView(); + } + + private static async Task ReadFileTextAsync(DataPackageView package) + { + CollectionAssert.Contains(package.AvailableFormats.ToArray(), StandardDataFormats.StorageItems); + var storageItems = await package.GetStorageItemsAsync(); + Assert.AreEqual(1, storageItems.Count); + + return await File.ReadAllTextAsync(storageItems.Single().Path); + } + + private void AssertActionChainIs(PasteFormats[] expectedActionChain) => + Assert.AreEqual(AdvancedPasteSemanticKernelFormatEvent.FormatActionChain(expectedActionChain), _eventListener.SemanticKernelEvents.Single().ActionChain); +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Utils/AdvancedPasteEventListener.cs b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Utils/AdvancedPasteEventListener.cs new file mode 100644 index 000000000000..39d14567155b --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Utils/AdvancedPasteEventListener.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using System.Linq; +using System.Text.Json; + +using AdvancedPaste.Telemetry; +using Microsoft.PowerToys.Telemetry; + +namespace AdvancedPaste.UnitTests.Utils; + +internal sealed class AdvancedPasteEventListener : EventListener +{ + private readonly List _customFormatEvents = []; + private readonly List _semanticKernelEvents = []; + + public IReadOnlyList CustomFormatEvents => _customFormatEvents; + + public IReadOnlyList SemanticKernelEvents => _semanticKernelEvents; + + public int CustomFormatTokens => _customFormatEvents.Sum(e => e.PromptTokens + e.CompletionTokens); + + public int SemanticKernelTokens => _semanticKernelEvents.Sum(e => e.PromptTokens + e.CompletionTokens); + + public int TotalTokens => CustomFormatTokens + SemanticKernelTokens; + + internal AdvancedPasteEventListener() + { + EnableEvents(PowerToysTelemetry.Log, EventLevel.LogAlways); + } + + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + if (eventData.EventSource.Name != PowerToysTelemetry.Log.Name) + { + return; + } + + var payloadDict = eventData.PayloadNames + .Zip(eventData.Payload) + .ToDictionary(tuple => tuple.First, tuple => tuple.Second); + + bool AddToListIfKeyExists(string key, List list) + { + if (payloadDict.ContainsKey(key)) + { + var payloadJson = JsonSerializer.Serialize(payloadDict); + list.Add(JsonSerializer.Deserialize(payloadJson)); + return true; + } + + return false; + } + + if (!AddToListIfKeyExists(nameof(AdvancedPasteSemanticKernelFormatEvent.ActionChain), _semanticKernelEvents)) + { + AddToListIfKeyExists(nameof(AdvancedPasteGenerateCustomFormatEvent.PromptTokens), _customFormatEvents); + } + } +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Utils/ResourceUtils.cs b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Utils/ResourceUtils.cs new file mode 100644 index 000000000000..62fa13c3be76 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Utils/ResourceUtils.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +using Windows.ApplicationModel.DataTransfer; +using Windows.Storage.Streams; + +namespace AdvancedPaste.UnitTests.Utils; + +internal static class ResourceUtils +{ + internal static async Task GetImageAssetAsDataPackageAsync(string resourceName) + { + var imageStreamRef = await ConvertToRandomAccessStreamReferenceAsync(GetImageResourceAsStream($"Assets/{resourceName}")); + + DataPackage package = new(); + package.SetBitmap(imageStreamRef); + return package; + } + + private static async Task ConvertToRandomAccessStreamReferenceAsync(Stream stream) + { + InMemoryRandomAccessStream inMemoryStream = new(); + using var inputStream = stream.AsInputStream(); + await RandomAccessStream.CopyAsync(inputStream, inMemoryStream); + + inMemoryStream.Seek(0); + return RandomAccessStreamReference.CreateFromStream(inMemoryStream); + } + + private static Stream GetImageResourceAsStream(string filename) + { + var assembly = Assembly.GetExecutingAssembly(); + var assemblyName = new AssemblyName(assembly.FullName ?? throw new InvalidOperationException()); + var resourceName = $"{assemblyName.Name}.{filename.Replace("/", ".")}"; + + return assembly.GetManifestResourceNames().Contains(resourceName) + ? assembly.GetManifestResourceStream(resourceName) + : throw new InvalidOperationException($"Embedded resource '{resourceName}' does not exist."); + } +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPaste.csproj b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPaste.csproj index c8ea965a4d7a..b67ebf2880df 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPaste.csproj +++ b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPaste.csproj @@ -48,6 +48,7 @@ + @@ -57,8 +58,9 @@ + - + @@ -86,6 +88,12 @@ + + + <_Parameter1>AdvancedPaste.UnitTests + + + diff --git a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/App.xaml.cs b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/App.xaml.cs index 3595276c5d51..3ac3baa9d0e6 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/App.xaml.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/App.xaml.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO.Abstractions; using System.Linq; using System.Reflection; using System.Threading; @@ -70,14 +71,19 @@ public App() Microsoft.Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = appLanguage; } - this.InitializeComponent(); + InitializeComponent(); Host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder().UseContentRoot(AppContext.BaseDirectory).ConfigureServices((context, services) => { + services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); }).Build(); viewModel = GetService(); @@ -257,7 +263,7 @@ protected virtual void Dispose(bool disposing) if (disposing) { EtwTrace?.Dispose(); - window.Dispose(); + window?.Dispose(); } disposedValue = true; diff --git a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PasteFormatTemplateSelector.cs b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PasteFormatTemplateSelector.cs new file mode 100644 index 000000000000..18f6b86f334f --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PasteFormatTemplateSelector.cs @@ -0,0 +1,29 @@ +// 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 AdvancedPaste.Models; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; + +namespace AdvancedPaste.Controls; + +public sealed partial class PasteFormatTemplateSelector : DataTemplateSelector +{ + public DataTemplate ItemTemplate { get; set; } + + public DataTemplate ItemTemplateDisabled { get; set; } + + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + bool isEnabled = item is PasteFormat pasteFormat && pasteFormat.IsEnabled; + + if (container is SelectorItem selector) + { + selector.IsEnabled = isEnabled; + } + + return isEnabled ? ItemTemplate : ItemTemplateDisabled; + } +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PromptBox.xaml b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PromptBox.xaml index 2c0d9ea93700..69f675d4cb06 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PromptBox.xaml +++ b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PromptBox.xaml @@ -173,11 +173,23 @@ Width="16" Height="16" Margin="8,0,0,0"> - + + + + + + + @@ -346,6 +361,7 @@ x:Name="InputTxtBox" HorizontalAlignment="Stretch" x:FieldModifier="public" + DataContext="{x:Bind ViewModel}" IsEnabled="{x:Bind ViewModel.ClipboardHasData, Mode=OneWay}" KeyDown="InputTxtBox_KeyDown" PlaceholderText="{x:Bind ViewModel.InputTxtBoxPlaceholderText, Mode=OneWay}" @@ -394,6 +410,7 @@ Spacing="2"> @@ -483,7 +501,7 @@ x:Uid="RegenerateBtnAutomation" Grid.Column="1" VerticalAlignment="Stretch" - Command="{x:Bind GenerateCustomCommand}" + Command="{x:Bind GenerateCustomAICommand}" Content="{ui:FontIcon Glyph=, FontSize=16}" Style="{StaticResource SubtleButtonStyle}"> @@ -508,34 +526,6 @@ - - - @@ -587,9 +578,9 @@ HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Transparent" - Visibility="{x:Bind ViewModel.IsCustomAIEnabled, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}"> + Visibility="{x:Bind ViewModel.IsCustomAIAvailable, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}"> - + @@ -634,11 +625,36 @@ - + + + + + + + + + + + - diff --git a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PromptBox.xaml.cs b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PromptBox.xaml.cs index b33f998cbf5f..3383af5292aa 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PromptBox.xaml.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Controls/PromptBox.xaml.cs @@ -2,10 +2,10 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.ComponentModel; using System.Threading.Tasks; -using AdvancedPaste.Helpers; using AdvancedPaste.Models; using AdvancedPaste.ViewModels; using CommunityToolkit.Mvvm.Input; @@ -40,7 +40,7 @@ public string PlaceholderText public object Footer { - get => (object)GetValue(FooterProperty); + get => GetValue(FooterProperty); set => SetValue(FooterProperty, value); } @@ -50,27 +50,24 @@ public PromptBox() ViewModel = App.GetService(); ViewModel.PropertyChanged += ViewModel_PropertyChanged; - ViewModel.CustomActionActivated += ViewModel_CustomActionActivated; + ViewModel.PreviewRequested += ViewModel_PreviewRequested; } private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(ViewModel.Busy) || e.PropertyName == nameof(ViewModel.PasteOperationErrorText)) + if (e.PropertyName == nameof(ViewModel.Busy) || e.PropertyName == nameof(ViewModel.PasteActionError)) { - var state = ViewModel.Busy ? "LoadingState" : string.IsNullOrEmpty(ViewModel.PasteOperationErrorText) ? "DefaultState" : "ErrorState"; + var state = ViewModel.Busy ? "LoadingState" : ViewModel.PasteActionError.HasText ? "ErrorState" : "DefaultState"; VisualStateManager.GoToState(this, state, true); } } - private void ViewModel_CustomActionActivated(object sender, CustomActionActivatedEventArgs e) + private void ViewModel_PreviewRequested(object sender, EventArgs e) { Logger.LogTrace(); - if (!e.PasteResult) - { - PreviewGrid.Width = InputTxtBox.ActualWidth; - PreviewFlyout.ShowAt(InputTxtBox); - } + PreviewGrid.Width = InputTxtBox.ActualWidth; + PreviewFlyout.ShowAt(InputTxtBox); } private void Grid_Loaded(object sender, RoutedEventArgs e) @@ -79,35 +76,19 @@ private void Grid_Loaded(object sender, RoutedEventArgs e) } [RelayCommand] - private async Task GenerateCustomAsync() => await ViewModel.GenerateCustomFunctionAsync(PasteActionSource.PromptBox); - - [RelayCommand] - private void Recall() - { - Logger.LogTrace(); - - InputTxtBox.IsEnabled = true; - - var lastQuery = ViewModel.RecallPreviousCustomQuery(); - if (lastQuery != null) - { - InputTxtBox.Text = lastQuery.Query; - } - - ClipboardHelper.SetClipboardTextContent(lastQuery.ClipboardData); - } + private async Task GenerateCustomAIAsync() => await ViewModel.ExecuteCustomAIFormatFromCurrentQueryAsync(PasteActionSource.PromptBox); private async void InputTxtBox_KeyDown(object sender, Microsoft.UI.Xaml.Input.KeyRoutedEventArgs e) { - if (e.Key == Windows.System.VirtualKey.Enter && InputTxtBox.Text.Length > 0 && ViewModel.IsCustomAIEnabled) + if (e.Key == Windows.System.VirtualKey.Enter && InputTxtBox.Text.Length > 0 && ViewModel.IsCustomAIAvailable) { - await GenerateCustomAsync(); + await GenerateCustomAIAsync(); } } - private void PreviewPasteBtn_Click(object sender, RoutedEventArgs e) + private async void PreviewPasteBtn_Click(object sender, RoutedEventArgs e) { - ViewModel.PasteCustom(); + await ViewModel.PasteCustomAsync(); } private void ThumbUpDown_Click(object sender, RoutedEventArgs e) diff --git a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/MainWindow.xaml.cs b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/MainWindow.xaml.cs index 6536bcfed97b..7743e6764bb2 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/MainWindow.xaml.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/MainWindow.xaml.cs @@ -43,7 +43,7 @@ void UpdateHeight() double GetHeight(int maxCustomActionCount) => baseHeight + new PasteFormatsToHeightConverter().GetHeight(coreActionCount + _userSettings.AdditionalActions.Count) + - new PasteFormatsToHeightConverter() { MaxItems = maxCustomActionCount }.GetHeight(optionsViewModel.IsAIServiceEnabled ? _userSettings.CustomActions.Count : 0); + new PasteFormatsToHeightConverter() { MaxItems = maxCustomActionCount }.GetHeight(optionsViewModel.IsCustomAIServiceEnabled ? _userSettings.CustomActions.Count : 0); MinHeight = GetHeight(1); Height = GetHeight(5); @@ -54,7 +54,7 @@ double GetHeight(int maxCustomActionCount) => _userSettings.Changed += (_, _) => UpdateHeight(); optionsViewModel.PropertyChanged += (_, e) => { - if (e.PropertyName == nameof(optionsViewModel.IsAIServiceEnabled)) + if (e.PropertyName == nameof(optionsViewModel.IsCustomAIServiceEnabled)) { UpdateHeight(); } @@ -82,6 +82,7 @@ double GetHeight(int maxCustomActionCount) => }; WindowHelpers.BringToForeground(this.GetWindowHandle()); + WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(this.GetWindowHandle()); } private void OnActivated(object sender, WindowActivatedEventArgs args) diff --git a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Pages/MainPage.xaml b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Pages/MainPage.xaml index b4e99ebaed94..a37e53f49ea4 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Pages/MainPage.xaml +++ b/src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Pages/MainPage.xaml @@ -21,6 +21,77 @@ x:Name="customActionsToMinHeightConverter" ValueIfNonZero="40" ValueIfZero="0" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - @@ -196,10 +216,10 @@ x:Name="PasteOptionsListView" Grid.Row="0" VerticalAlignment="Bottom" - IsItemClickEnabled="False" - ItemContainerStyle="{StaticResource PasteFormatListViewItemStyle}" + IsItemClickEnabled="True" + ItemClick="PasteFormat_ItemClick" ItemContainerTransitions="{x:Null}" - ItemTemplate="{StaticResource PasteFormatTemplate}" + ItemTemplateSelector="{StaticResource PasteFormatTemplateSelector}" ItemsSource="{x:Bind ViewModel.StandardPasteFormats, Mode=OneWay}" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Auto" @@ -217,10 +237,10 @@ x:Name="CustomActionsListView" Grid.Row="2" VerticalAlignment="Top" - IsItemClickEnabled="False" - ItemContainerStyle="{StaticResource PasteFormatListViewItemStyle}" + IsItemClickEnabled="True" + ItemClick="PasteFormat_ItemClick" ItemContainerTransitions="{x:Null}" - ItemTemplate="{StaticResource PasteFormatTemplate}" + ItemTemplateSelector="{StaticResource PasteFormatTemplateSelector}" ItemsSource="{x:Bind ViewModel.CustomActionPasteFormats, Mode=OneWay}" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Auto" @@ -232,7 +252,6 @@ Height="1" HorizontalAlignment="Stretch" Fill="{ThemeResource DividerStrokeColorDefaultBrush}" /> -