* Update README.md

* Espresso (#11245)

* Revert "Merge branch 'microsoft:master' into master"

This reverts commit b080908712, reversing
changes made to 8463c95a43.

* Fix conversion of settings in the UX

* Update terminology

* Updating logging configuration

* Set up how tray and setting configuration works

* Adding hero images

* Fix how binding works

* Update OOBE string

* Fix spelling error

* fixing dep to include espresso, adding in yml

* Update API components and fix display keep-awake bug

* Adding words that the spell check is yelling about

* tweak wsx

* Change default setting for Espresso

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>

* Update Product.wxs

* Update Shortcut.cpp

* Update with more logging (#11332)

* Revert "Merge branch 'microsoft:master' into master"

This reverts commit b080908712, reversing
changes made to 8463c95a43.

* Fix conversion of settings in the UX

* Update terminology

* Updating logging configuration

* Set up how tray and setting configuration works

* Adding hero images

* Fix how binding works

* Update OOBE string

* Fix spelling error

* fixing dep to include espresso, adding in yml

* Update API components and fix display keep-awake bug

* Adding words that the spell check is yelling about

* tweak wsx

* Change default setting for Espresso

* Adding some extra logging

* Update Shortcut.cpp

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>

* Fix minor issue in the module branch (#11340)

* Revert "Merge branch 'microsoft:master' into master"

This reverts commit b080908712, reversing
changes made to 8463c95a43.

* Fix conversion of settings in the UX

* Update terminology

* Updating logging configuration

* Set up how tray and setting configuration works

* Adding hero images

* Fix how binding works

* Update OOBE string

* Fix spelling error

* fixing dep to include espresso, adding in yml

* Update API components and fix display keep-awake bug

* Adding words that the spell check is yelling about

* tweak wsx

* Change default setting for Espresso

* Adding some extra logging

* Update Shortcut.cpp

* Fix log location coming from the runner

* More chatty logging for console allocation

* Installer config to add the missing assets

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>

* Update Product.wxs

* Update Program.cs

* fixing typo

* removing a unneeded removal

* [Espresso] More minor tweaks to logging (#11341)

* Revert "Merge branch 'microsoft:master' into master"

This reverts commit b080908712, reversing
changes made to 8463c95a43.

* Fix conversion of settings in the UX

* Update terminology

* Updating logging configuration

* Set up how tray and setting configuration works

* Adding hero images

* Fix how binding works

* Update OOBE string

* Fix spelling error

* fixing dep to include espresso, adding in yml

* Update API components and fix display keep-awake bug

* Adding words that the spell check is yelling about

* tweak wsx

* Change default setting for Espresso

* Adding some extra logging

* Update Shortcut.cpp

* Fix log location coming from the runner

* More chatty logging for console allocation

* Installer config to add the missing assets

* Remove unused handle codes

* Update log file name for the Espresso C++ code.

* Update the project configuration to fix build issue

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>

* Update patterns.txt

* Fix binding issues (#11368)

* Revert "Merge branch 'microsoft:master' into master"

This reverts commit b080908712, reversing
changes made to 8463c95a43.

* Fix conversion of settings in the UX

* Update terminology

* Updating logging configuration

* Set up how tray and setting configuration works

* Adding hero images

* Fix how binding works

* Update OOBE string

* Fix spelling error

* fixing dep to include espresso, adding in yml

* Update API components and fix display keep-awake bug

* Adding words that the spell check is yelling about

* tweak wsx

* Change default setting for Espresso

* Adding some extra logging

* Update Shortcut.cpp

* Fix log location coming from the runner

* More chatty logging for console allocation

* Installer config to add the missing assets

* Remove unused handle codes

* Update log file name for the Espresso C++ code.

* Update the project configuration to fix build issue

* Fix binding issue with the time settings

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>

* Introduce the off mode and fix binding issues (#11385)

* Revert "Merge branch 'microsoft:master' into master"

This reverts commit b080908712, reversing
changes made to 8463c95a43.

* Fix conversion of settings in the UX

* Update terminology

* Updating logging configuration

* Set up how tray and setting configuration works

* Adding hero images

* Fix how binding works

* Update OOBE string

* Fix spelling error

* fixing dep to include espresso, adding in yml

* Update API components and fix display keep-awake bug

* Adding words that the spell check is yelling about

* tweak wsx

* Change default setting for Espresso

* Adding some extra logging

* Update Shortcut.cpp

* Fix log location coming from the runner

* More chatty logging for console allocation

* Installer config to add the missing assets

* Remove unused handle codes

* Update log file name for the Espresso C++ code.

* Update the project configuration to fix build issue

* Fix binding issue with the time settings

* Proper Espresso behavior for binding

* Fix settings UI

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>

* Update with missing strings. (#11386)

* Revert "Merge branch 'microsoft:master' into master"

This reverts commit b080908712, reversing
changes made to 8463c95a43.

* Fix conversion of settings in the UX

* Update terminology

* Updating logging configuration

* Set up how tray and setting configuration works

* Adding hero images

* Fix how binding works

* Update OOBE string

* Fix spelling error

* fixing dep to include espresso, adding in yml

* Update API components and fix display keep-awake bug

* Adding words that the spell check is yelling about

* tweak wsx

* Change default setting for Espresso

* Adding some extra logging

* Update Shortcut.cpp

* Fix log location coming from the runner

* More chatty logging for console allocation

* Installer config to add the missing assets

* Remove unused handle codes

* Update log file name for the Espresso C++ code.

* Update the project configuration to fix build issue

* Fix binding issue with the time settings

* Proper Espresso behavior for binding

* Fix settings UI

* Re-add missing strings

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>

* Fix whitespace issue (#11387)

* Revert "Merge branch 'microsoft:master' into master"

This reverts commit b080908712, reversing
changes made to 8463c95a43.

* Fix conversion of settings in the UX

* Update terminology

* Updating logging configuration

* Set up how tray and setting configuration works

* Adding hero images

* Fix how binding works

* Update OOBE string

* Fix spelling error

* fixing dep to include espresso, adding in yml

* Update API components and fix display keep-awake bug

* Adding words that the spell check is yelling about

* tweak wsx

* Change default setting for Espresso

* Adding some extra logging

* Update Shortcut.cpp

* Fix log location coming from the runner

* More chatty logging for console allocation

* Installer config to add the missing assets

* Remove unused handle codes

* Update log file name for the Espresso C++ code.

* Update the project configuration to fix build issue

* Fix binding issue with the time settings

* Proper Espresso behavior for binding

* Fix settings UI

* Re-add missing strings

* Fix whitespace issue

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>

* Fix default (#11388)

* Revert "Merge branch 'microsoft:master' into master"

This reverts commit b080908712, reversing
changes made to 8463c95a43.

* Fix conversion of settings in the UX

* Update terminology

* Updating logging configuration

* Set up how tray and setting configuration works

* Adding hero images

* Fix how binding works

* Update OOBE string

* Fix spelling error

* fixing dep to include espresso, adding in yml

* Update API components and fix display keep-awake bug

* Adding words that the spell check is yelling about

* tweak wsx

* Change default setting for Espresso

* Adding some extra logging

* Update Shortcut.cpp

* Fix log location coming from the runner

* More chatty logging for console allocation

* Installer config to add the missing assets

* Remove unused handle codes

* Update log file name for the Espresso C++ code.

* Update the project configuration to fix build issue

* Fix binding issue with the time settings

* Proper Espresso behavior for binding

* Fix settings UI

* Re-add missing strings

* Fix whitespace issue

* Fix the default mode of operation

Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>

* Update Microsoft.PowerToys.Settings.UI.csproj

* Localization improvements

* Replaced a computer with your pc

* Updated Espresso imagery

* Fixed inconsistent string

* Margin fix and updated images

* Removed unused code

Co-authored-by: Den Delimarsky <1389609+dend@users.noreply.github.com>
Co-authored-by: Niels Laute <niels9001@hotmail.com>
Co-authored-by: crutkas <crutkas@microsoft.com>
Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com>
This commit is contained in:
Clint Rutkas 2021-05-25 10:13:04 -07:00 committed by GitHub
parent 6821c50ffe
commit 894f469de6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 2399 additions and 99 deletions

View File

@ -59,7 +59,6 @@ APeriod
api
APIENTRY
APIIs
apos
APPBARDATA
appcontainer
appdata
@ -87,6 +86,7 @@ args
argv
Arial
arik
Arity
arjunbalgovind
ARPINSTALLLOCATION
ARPPRODUCTICON
@ -124,13 +124,13 @@ Autorun
AUTOSIZECOLUMNS
autoupdate
AValid
AWAYMODE
azurecr
azurewebsites
backend
backtracer
bak
bbwe
bc
bcc
bck
Bcl
@ -140,7 +140,6 @@ betsegaw
BGR
bgra
BGSOUNDS
bh
bhid
Bicubic
bigbar
@ -217,7 +216,6 @@ CHECKCANCELED
CHILDACTIVATE
CHILDWINDOW
chrdavis
Chris's
chrono
Chrzan
CHT
@ -226,7 +224,6 @@ cinttypes
cla
clangformat
CLASSDC
classmethod
classname
CLASSNOTAVAILABLE
clickable
@ -237,7 +234,7 @@ clientside
CLIPCHILDREN
CLIPSIBLINGS
clrcall
cls
Cls
CLSCTX
clsid
CMDARG
@ -251,7 +248,6 @@ CMINVOKECOMMANDINFOEX
CMock
CMONITORS
cmyk
cn
cnt
coclass
codebase
@ -285,6 +281,7 @@ config
CONFLICTINGMODIFIERKEY
CONFLICTINGMODIFIERSHORTCUT
Connectquickaction
CONOUT
Consolas
constexpr
contentdialog
@ -355,7 +352,6 @@ CUSTOMACTIONTEST
cvd
cwchar
cwd
cx
cxfksword
CXSMICON
CXVIRTUALSCREEN
@ -363,7 +359,6 @@ cxx
cxxopts
CYMK
CYSMICON
cz
cziplib
Dac
dacl
@ -428,7 +423,6 @@ devblogs
devdocs
devenum
DEVMON
df
DFactory
diffing
difftime
@ -481,7 +475,6 @@ dutil
DVASPECT
DVASPECTINFO
DVTARGETDEVICE
dw
DWindow
DWINRT
DWLP
@ -500,7 +493,6 @@ dworigin
dwrite
dxgi
Easeof
EB
ecef
ecount
EDB
@ -540,12 +532,12 @@ errorlevel
ERRORMESSAGE
ERRORTITLE
esize
espressoversion
estdir
etcore
etl
etw
EUQ
ev
evenodd
eventlog
everytime
@ -586,7 +578,6 @@ FANCYZONESDRAWLAYOUTTEST
FANCYZONESEDITOR
Farbraum
FARPROC
fd
feimage
ffcd
FFDDDDDD
@ -614,7 +605,7 @@ Fle
fluentui
flyout
fmtlib
fody
Fody
FOF
FOFX
FOLDERID
@ -634,7 +625,6 @@ fullscreen
func
fwlink
fwrite
fx
fxcop
gabime
GAC
@ -652,12 +642,10 @@ GETDPISCALEDSIZE
GETEMPTYMARKUP
GETICON
getline
getmembers
GETMINMAXINFO
GETSTATE
GETTEXT
GETTEXTLENGTH
gh
github
githubusercontent
gitignore
@ -684,7 +672,6 @@ hbitmap
hbmp
hbr
HBRUSH
hc
hcblack
hcwhite
hdc
@ -698,7 +685,6 @@ HDS
HEB
helptext
HGLOBAL
hh
hhk
HHmmss
HHOOK
@ -710,7 +696,6 @@ hinst
hinstance
hitinfo
HIWORD
hk
HKCC
HKCR
HKCU
@ -755,7 +740,6 @@ Htmdid
html
htt
http
hu
hwb
HWINEVENTHOOK
hwnd
@ -908,7 +892,6 @@ iobjectwithsitesetsite
IOle
iolewindowcontextsensitivehelp
iostream
ip
IPackage
IPath
ipc
@ -945,7 +928,6 @@ isfinite
IShell
ISingle
ISmart
ismethod
isocpp
IStorage
IStream
@ -982,7 +964,6 @@ jfif
jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi
jjw
jobject
jp
jpe
jpeg
jpg
@ -1017,17 +998,16 @@ keystokes
Keystool
Keytool
keyup
Kf
KILLFOCUS
Knownfolders
Kybd
LAlt
lambson
Lambson
lamotile
langword
Lastdevice
LASTEXITCODE
laute
Laute
laviusmotileng
LAYOUTRTL
LBUTTON
@ -1071,7 +1051,6 @@ lmcons
LMEM
LMENU
lnk
loadingbar
LOCALAPPDATA
LOCALDISPLAY
localhost
@ -1080,6 +1059,8 @@ localport
localtime
LOCATIONCHANGE
Lockyour
logconsole
logfile
LOGFONT
LOGMSG
logon
@ -1178,7 +1159,6 @@ Mensching
menuitem
MENUITEMINFO
MENUITEMINFOW
messagebox
messageboxes
METACHARSET
metadata
@ -1194,6 +1174,7 @@ mimetype
Minimizeallwindows
MINIMIZEBOX
miniz
minlevel
MINMAXINFO
Miracast
MJPG
@ -1306,7 +1287,7 @@ niels
nielslaute
NIF
NLD
NLog
nlog
NLSTEXT
NMLVEMPTYMARKUP
NOACTIVATE
@ -1370,7 +1351,6 @@ NUMPAD
nunit
Nvidia
NWSE
NX
Objbase
OBJID
objidl
@ -1413,6 +1393,7 @@ otating
OUTOFCONTEXT
OUTOFMEMORY
Outptr
outputtype
outro
outsettings
OVERLAPPEDWINDOW
@ -1432,7 +1413,6 @@ PARENTRELATIVEPARSING
parray
PARTIALCONFIRMATIONDIALOGTITLE
pathcch
pb
pbc
Pbgra
pcb
@ -1476,7 +1456,6 @@ plugin
pluginsmodel
plvdi
PMSIHANDLE
Pn
png
pnm
pnmdr
@ -1562,15 +1541,11 @@ ptstr
pubxml
Pui
pushd
pv
PVOID
pw
pwa
pwcs
PWSTR
pwtd
px
QI
qianlifeng
qit
QITAB
@ -1672,7 +1647,7 @@ roadmap
Roboto
roslyn
royvou
rpc
Rpc
RRF
rshift
Rsp
@ -1682,7 +1657,6 @@ RTB
rtf
Rtl
RTLREADING
ru
ruleset
RUNACTIVEXCTLS
runas
@ -1693,12 +1667,10 @@ runsettings
runtimeclass
runtimeconfig
runtimes
rv
RUS
rvalue
rvm
rwin
rx
ryanbodrug
saahmedm
sacl
@ -1823,6 +1795,7 @@ spdlog
spdo
spdth
spec'ing
specialfolder
spesi
splitwstring
sppd
@ -1927,8 +1900,7 @@ syslog
SYSMENU
systemd
SYSTEMTIME
sz
tadele
Tadele
Tahoma
talynone
TApp
@ -1950,7 +1922,6 @@ tbody
tchar
tcscpy
TCustom
td
TDevice
Templated
templatenamespace
@ -1987,6 +1958,7 @@ toggleswitch
toolbar
Toolchain
toolset
toolstrip
tooltip
toolwindow
TOPDOWNDIB
@ -2003,8 +1975,6 @@ trl
trunc
TStr
tsx
tt
tw
TYMED
typedef
TYPEKEY
@ -2013,7 +1983,6 @@ typename
typeof
typeparam
TYPESHORTCUT
Tz
UAC
UAL
uap
@ -2027,7 +1996,6 @@ uintptr
UIPI
UIs
UITo
ul
ULARGE
ULLONG
ulong
@ -2086,7 +2054,6 @@ utf
utils
uuid
uuidof
uv
uwp
UWPUI
uxtheme
@ -2108,7 +2075,6 @@ verrsrc
VERSIONINFO
Versioning
VFT
vh
vid
VIDEOINFOHEADER
viewbox
@ -2118,10 +2084,8 @@ visiblecolorformats
Visibletrue
visualbrush
visualstudio
vk
VKey
VKTAB
vm
vmax
vmin
VOS
@ -2137,8 +2101,6 @@ VSTHRD
VSTT
VTABLE
Vtbl
vw
Vx
watsonportal
wav
WBounds
@ -2193,6 +2155,8 @@ windowsx
windowwalker
winerror
WINEVENT
winexe
winforms
winfx
winget
Winhook
@ -2256,7 +2220,6 @@ WTSAT
Wwan
www
wxs
xa
xamarin
xaml
XAttribute
@ -2281,11 +2244,11 @@ XOffset
xpath
XResource
xsd
xsi
XSmall
XStr
XToolset
xunit
XY
Yaml
YDiff
YESNO
@ -2296,13 +2259,9 @@ YOffset
YStr
YUY
YUYV
yy
Zc
ZEROINIT
zh
ZIndex
zipfolder
zm
zonable
ZONECOLOR
ZONEHIGHLIGHTCOLOR

View File

@ -31,6 +31,8 @@ TestCase\("[^"]+"
# Windows paths
\\native
\\netcoreapp
\\netstandard
\\notifications
\\recyclebin
\\reinstall
@ -41,6 +43,7 @@ TestCase\("[^"]+"
\\restore
\\result
\\runner
\\runtimes
\\Telemetry
\\telemetry
\\testapp

View File

@ -75,6 +75,13 @@ build:
- 'modules\ColorPicker\PowerToysInterop.dll'
- 'modules\ColorPicker\Telemetry.dll'
- '**\*.resources.dll'
- 'modules\Espresso\EspressoModuleInterface.dll'
- 'modules\Espresso\ManagedCommon.dll'
- 'modules\Espresso\ManagedTelemetry.dll'
- 'modules\Espresso\Microsoft.PowerToys.Settings.UI.Lib.dll'
- 'modules\Espresso\PowerToys.Espresso.exe'
- 'modules\Espresso\PowerToys.Espresso.dll'
- 'modules\Espresso\PowerToysInterop.dll'
- 'modules\FancyZones\fancyzones.dll'
- 'modules\FancyZones\FancyZonesEditor.exe'
- 'modules\FancyZones\FancyZonesEditor.dll'
@ -102,6 +109,7 @@ build:
- 'modules\KeyboardManager\KeyboardManagerEngine\PowerToys.KeyboardManagerEngine.exe'
- 'modules\launcher\Microsoft.PowerToys.Settings.UI.Lib.dll'
- 'modules\launcher\ManagedCommon.dll'
- 'modules\launcher\ManagedTelemetry.dll'
- 'modules\launcher\Microsoft.PowerToys.Common.UI.dll'
- 'modules\launcher\Microsoft.Launcher.dll'
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Calculator\Microsoft.PowerToys.Run.Plugin.Calculator.dll'

View File

@ -16,11 +16,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner
{BA58206B-1493-4C75-BFEA-A85768A1E156} = {BA58206B-1493-4C75-BFEA-A85768A1E156}
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB}
{E364F67B-BB12-4E91-B639-355866EBCD8B} = {E364F67B-BB12-4E91-B639-355866EBCD8B}
{D940E07F-532C-4FF3-883F-790DA014F19A} = {D940E07F-532C-4FF3-883F-790DA014F19A}
{DA425894-6E13-404F-8DCB-78584EC0557A} = {DA425894-6E13-404F-8DCB-78584EC0557A}
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} = {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}
{A7D5099E-F0FD-4BF3-8522-5A682759F915} = {A7D5099E-F0FD-4BF3-8522-5A682759F915}
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B} = {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {B25AC7A5-FB9F-4789-B392-D5C85E948670}
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {5E7360A8-D048-4ED3-8F09-0BFD64C5529A}
{AF2349B8-E5B6-4004-9502-687C1C7730B1} = {AF2349B8-E5B6-4004-9502-687C1C7730B1}
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}
@ -321,6 +323,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorLibrar
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorTest", "src\modules\keyboardmanager\KeyboardManagerEditorTest\KeyboardManagerEditorTest.vcxproj", "{62173D9A-6724-4C00-A1C8-FB646480A9EC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "espresso", "espresso", "{127F38E0-40AA-4594-B955-5616BF206882}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EspressoModuleInterface", "src\modules\espresso\EspressoModuleInterface\EspressoModuleInterface.vcxproj", "{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Espresso", "src\modules\espresso\Espresso\Espresso.csproj", "{D940E07F-532C-4FF3-883F-790DA014F19A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shortcutguide", "shortcutguide", "{106CBECA-0701-4FC3-838C-9DF816A19AE2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuideModuleInterface", "src\modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.vcxproj", "{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}"
@ -659,6 +667,14 @@ Global
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.Build.0 = Debug|x64
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.ActiveCfg = Release|x64
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.Build.0 = Release|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.ActiveCfg = Debug|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.Build.0 = Debug|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.ActiveCfg = Release|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.Build.0 = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.ActiveCfg = Debug|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.Build.0 = Debug|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.ActiveCfg = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.Build.0 = Release|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.ActiveCfg = Debug|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.Build.0 = Debug|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.ActiveCfg = Release|x64
@ -765,6 +781,9 @@ Global
{8DF78B53-200E-451F-9328-01EB907193AE} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{127F38E0-40AA-4594-B955-5616BF206882} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {127F38E0-40AA-4594-B955-5616BF206882}
{D940E07F-532C-4FF3-883F-790DA014F19A} = {127F38E0-40AA-4594-B955-5616BF206882}
{106CBECA-0701-4FC3-838C-9DF816A19AE2} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
{2EDB3EB4-FA92-4BFF-B2D8-566584837231} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}

View File

@ -19,7 +19,7 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
| [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) | [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) |
| [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) |
| [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Video Conference Mute (Experimental)](https://aka.ms/PowerToysOverview_VideoConference) |
| espresso | | |
## Installing and running Microsoft PowerToys
### Requirements

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

View File

@ -2,11 +2,13 @@
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" >
<!-- Names of folders and projects -->
<?define FancyZonesProjectName="FancyZones"?>
<?define ImageResizerProjectName="ImageResizer"?>
<?define KeyboardManagerProjectName="KeyboardManager"?>
<?define PowerRenameProjectName="PowerRename"?>
<?define ColorPickerProjectName="ColorPicker"?>
<?define EspressoProjectName="Espresso"?>
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
@ -218,16 +220,37 @@
</Directory>
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
<Directory Id="EspressoInstallFolder" Name="$(var.EspressoProjectName)">
<Directory Id="EspressoInstallFolderRuntimes" Name="Runtimes">
<Directory Id="EspressoInstallFolderRuntimesWin" Name="Win">
<Directory Id="EspressoInstallFolderRuntimesWinLib" Name="Lib">
<Directory Id="EspressoInstallFolderNetcoreApp21" Name="netcoreapp2.1" />
<Directory Id="EspressoInstallFolderNetcoreApp30" Name="netcoreapp3.0" />
<Directory Id="EspressoInstallFolderNetStandard20" Name="netstandard2.0" />
</Directory>
</Directory>
</Directory>
</Directory>
<!-- KBM -->
<Directory Id="KeyboardManagerInstallFolder" Name="$(var.KeyboardManagerProjectName)">
<Directory Id="KeyboardManagerEditorInstallFolder" Name="KeyboardManagerEditor" />
<Directory Id="KeyboardManagerEngineInstallFolder" Name="KeyboardManagerEngine" />
</Directory>
<!-- Color Picker -->
<Directory Id="ColorPickerInstallFolder" Name="$(var.ColorPickerProjectName)">
<Directory Id="ColorPickerResourcesFolder" Name="Resources"/>
</Directory>
<!-- Launcher -->
<Directory Id="LauncherInstallFolder" Name="launcher">
<Directory Id="AssetsFolder" Name="Assets" />
<Directory Id="LauncherImagesFolder" Name="Images" />
<Directory Id="LauncherPropertiesFolder" Name="Properties" />
<!-- Plugins -->
<Directory Id="LauncherPluginsFolder" Name="Plugins">
<Directory Id="CalculatorPluginFolder" Name="Calculator">
<Directory Id="CalculatorImagesFolder" Name="Images" />
@ -272,9 +295,10 @@
<Directory Id="SystemImagesFolder" Name="Images" />
</Directory>
</Directory>
<Directory Id="LauncherPropertiesFolder" Name="Properties" />
</Directory>
</Directory>
<!-- Settings -->
<Directory Id="SettingsV2InstallFolder" Name="Settings">
<Directory Id="SettingsV2ViewsInstallFolder" Name="Views"/>
<Directory Id="SettingsV2StylesInstallFolder" Name="Styles"/>
@ -361,6 +385,7 @@
</Component>
</DirectoryRef>
<!-- Shortcut guide files -->
<DirectoryRef Id="ShortcutGuideSvgsInstallFolder" FileSource="$(var.ShortcutGuideExecutable)\svgs\">
<Component Id="ShortcutGuideSvgs" Guid="7C4D4EED-9338-423D-992C-DCE02F3E2D35" Win64="yes">
<File Source="$(var.ShortcutGuideExecutable)\svgs\0.svg" />
@ -378,6 +403,8 @@
<File Source="$(var.ShortcutGuideExecutable)\svgs\overlay_portrait.svg" />
</Component>
</DirectoryRef>
<!-- FancyZone -->
<DirectoryRef Id="FancyZonesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
<Component Id="Module_FancyZones" Guid="C6B5272E-6ED4-4B80-B0E7-2FF0355D8CF4" Win64="yes">
<File Source="$(var.BinX64Dir)modules\$(var.FancyZonesProjectName)\fancyzones.dll" KeyPath="yes" />
@ -483,6 +510,7 @@
</Component>
</DirectoryRef>
<!-- Image Resizer -->
<DirectoryRef Id="ImageResizerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)">
<Component Id="Module_ImageResizer" Guid="96E63289-759C-4A73-A56B-EE7429932F72" Win64="yes">
<File Source="$(var.BinX64Dir)modules\$(var.ImageResizerProjectName)\ImageResizer.exe" />
@ -512,6 +540,7 @@
<RegistryValue Value="[ImageResizerInstallFolder]ImageResizerExt.dll" Type="string" />
<RegistryValue Name="ThreadingModel" Value="Apartment" Type="string" />
</RegistryKey>
<!-- Registry Key for the drag and drop handler -->
<RegistryValue Root="HKCR"
Key="Directory\ShellEx\DragDropHandlers\ImageResizer"
@ -573,6 +602,7 @@
</Component>
</DirectoryRef>
<!-- PowerRename -->
<DirectoryRef Id="PowerRenameInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)">
<Component Id="Module_PowerRename" Guid="E4401D08-27FE-4F96-BA17-0C61FD79E684" Win64="yes">
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRenameExt.dll" KeyPath="yes" />
@ -588,6 +618,7 @@
</Component>
</DirectoryRef>
<!-- Shortcut guide -->
<DirectoryRef Id="ShortcutGuideModuleInterfaceInstallFolder" FileSource="$(var.ShortcutGuideModuleInterface)">
<Component Id="Module_ShortcutGuideModuleInterface" Guid="CBD0AC09-91D3-428E-B2B3-05745ADF3473" Win64="yes">
<File Source="$(var.ShortcutGuideModuleInterface)\ShortcutGuideModuleInterface.dll" KeyPath="yes" />
@ -600,24 +631,28 @@
</Component>
</DirectoryRef>
<!-- KBM -->
<DirectoryRef Id="KeyboardManagerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\">
<Component Id="Module_KeyboardManager" Guid="9279BD82-786F-4F0B-8E49-DB484EE34C9B" Win64="yes">
<File Source="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManager.dll" />
</Component>
</DirectoryRef>
<!-- KBM Editor -->
<DirectoryRef Id="KeyboardManagerEditorInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManagerEditor">
<Component Id="Module_KeyboardManager_Editor" Guid="1240F1B8-17FE-4D68-B9AF-91882B0B1933" Win64="yes">
<File Source="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManagerEditor\PowerToys.KeyboardManagerEditor.exe" />
</Component>
</DirectoryRef>
<!-- KBM Engine -->
<DirectoryRef Id="KeyboardManagerEngineInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManagerEngine">
<Component Id="Module_KeyboardManager_Engine" Guid="14DBAA38-B98D-431F-9439-8EDE1C0670DB" Win64="yes">
<File Source="$(var.BinX64Dir)modules\$(var.KeyboardManagerProjectName)\KeyboardManagerEngine\PowerToys.KeyboardManagerEngine.exe" />
</Component>
</DirectoryRef>
<!-- Color Picker -->
<DirectoryRef Id="ColorPickerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)">
<Component Id="Module_ColorPicker" Guid="8A52A69E-37B2-4BEA-9D73-77763066052F" Win64="yes">
<?foreach File in ColorPicker.dll;System.IO.Abstractions.dll;ColorPickerUI.exe;ColorPickerUI.dll;ColorPickerUI.deps.json;ColorPickerUI.runtimeconfig.json;Microsoft.PowerToys.Settings.UI.Lib.dll;PowerToysInterop.dll;System.Text.Json.dll;ManagedTelemetry.dll;ManagedCommon.dll;ControlzEx.dll;Microsoft.Xaml.Behaviors.dll;ModernWpf.Controls.dll;ModernWpf.dll;System.ComponentModel.Composition.dll;Microsoft.PowerToys.Common.UI.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Text.Encodings.Web.dll?>
@ -626,6 +661,7 @@
</Component>
</DirectoryRef>
<!-- Color Picker Resources -->
<DirectoryRef Id="ColorPickerResourcesFolder" FileSource="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)\Resources">
<Component Id="Module_ColorPicker_Resources" Guid="7544BD0F-1DB6-4C53-89D3-ADAD472FDCC1">
<?foreach File in colorPicker.cur;icon.ico?>
@ -633,7 +669,39 @@
<?endforeach?>
</Component>
</DirectoryRef>
<!-- Espresso -->
<DirectoryRef Id="EspressoInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.EspressoProjectName)">
<Component Id="Module_Espresso" Guid="F26F5780-5B38-43B2-BC21-8406ED6E2071" Win64="yes">
<?foreach File in EspressoModuleInterface.dll;ManagedCommon.dll;ManagedTelemetry.dll;Microsoft.PowerToys.Settings.UI.Lib.dll;Microsoft.Win32.Registry.dll;Microsoft.Win32.SystemEvents.dll;NLog.config;NLog.dll;PowerToys.Espresso.deps.json;PowerToys.Espresso.dll;PowerToys.Espresso.exe;PowerToys.Espresso.runtimeconfig.json;PowerToysInterop.dll;System.CommandLine.dll;System.Configuration.ConfigurationManager.dll;System.Drawing.Common.dll;System.IO.Abstractions.dll;System.Reactive.dll;System.Runtime.Caching.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Security.AccessControl.dll;System.Security.Cryptography.ProtectedData.dll;System.Security.Permissions.dll;System.Security.Principal.Windows.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;System.Windows.Extensions.dll?>
<File Id="EspressoFile_$(var.File)" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\$(var.File)" />
<?endforeach?>
</Component>
</DirectoryRef>
<DirectoryRef Id="EspressoInstallFolderNetStandard20" FileSource="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netstandard2.0">
<Component Id="Module_Espresso_runtime_netstandard20" Guid="414A31AB-91A8-4F17-9B4B-DB7B93A2BB23">
<File Id="EspressoFile_runtime_Microsoft.Win32.Registry.dll" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netstandard2.0\Microsoft.Win32.Registry.dll" />
<File Id="EspressoFile_runtime_System.Runtime.Caching.dll" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netstandard2.0\System.Runtime.Caching.dll" />
<File Id="EspressoFile_runtime_System.Security.AccessControl.dll" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netstandard2.0\System.Security.AccessControl.dll" />
<File Id="EspressoFile_runtime_System.Security.Cryptography.ProtectedData.dll" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netstandard2.0\System.Security.Cryptography.ProtectedData.dll" />
</Component>
</DirectoryRef>
<DirectoryRef Id="EspressoInstallFolderNetcoreApp30" FileSource="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netcoreapp3.0">
<Component Id="Module_Espresso_runtime_netcoreapp30" Guid="1EBB21FE-083A-4AE6-9208-7DC72A421860">
<File Id="EspressoFile_runtime_Microsoft.Win32.SystemEvents.dll" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netcoreapp3.0\Microsoft.Win32.SystemEvents.dll" />
<File Id="EspressoFile_runtime_System.Drawing.Common.dll" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netcoreapp3.0\System.Drawing.Common.dll" />
<File Id="EspressoFile_runtime_System.Windows.Extensions.dll" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netcoreapp3.0\System.Windows.Extensions.dll" />
</Component>
</DirectoryRef>
<DirectoryRef Id="EspressoInstallFolderNetcoreApp21" FileSource="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netcoreapp2.1">
<Component Id="Module_Espresso_runtime_netcoreapp21" Guid="52ED2831-6F3F-47D3-AA1A-88C697BE9D0F">
<File Id="EspressoFile_runtime_System.Security.Principal.Windows.dll" Source="$(var.BinX64Dir)modules\$(var.EspressoProjectName)\runtimes\win\lib\netcoreapp2.1\System.Security.Principal.Windows.dll" />
</Component>
</DirectoryRef>
<DirectoryRef Id="FileExplorerPreviewInstallFolder" FileSource="$(var.RepoDir)\modules\FileExplorerPreview\">
<Component Id="Module_PowerPreview" Guid="FF1700D5-1B07-4E07-9A62-4D206645EEA9" Win64="yes">
<!-- Component to include PowerPreview Module Source dll's -->
@ -711,22 +779,22 @@
</DirectoryRef>
<DirectoryRef Id="SettingsV2AssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules">
<Component Id="SettingsV2AssetsModules" Guid="A0B961A9-77D0-4223-88A9-E3B41BD9C329" Win64="yes">
<?foreach File in ColorPicker.png;FancyZones.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png?>
<File Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" />
<?foreach File in ColorPicker.png;FancyZones.png;Espresso.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png?>
<File Id="SettingsV2AssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" />
<?endforeach?>
</Component>
</DirectoryRef>
<DirectoryRef Id="SettingsV2OOBEAssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules\OOBE">
<Component Id="SettingsV2OOBEAssetsModules" Guid="E2360A83-6694-4B33-B5F6-641A906359EE" Win64="yes">
<?foreach File in ColorPicker.gif;FancyZones.gif;FileExplorer.png;ImageResizer.gif;KBM.gif;PowerRename.gif;Run.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
<File Source="$(var.BinX64Dir)Settings\Assets\Modules\OOBE\$(var.File)" />
<?foreach File in ColorPicker.gif;Espresso.png;FancyZones.gif;FileExplorer.png;ImageResizer.gif;KBM.gif;PowerRename.gif;Run.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
<File Id="SettingsV2OOBEAssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\OOBE\$(var.File)" />
<?endforeach?>
</Component>
</DirectoryRef>
<DirectoryRef Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\FluentIcons">
<Component Id="SettingsV2OOBEAssetsFluentIcons" Guid="6A380D5A-DA63-45B5-B68F-06D57CDD1B9C" Win64="yes">
<?foreach File in ColorPicker.png;FancyZones.png;FileExplorerPreview.png;ImageResizer.png;KeyboardManager.png;PowerRename.png;PowerToys.png;PowerToysRun.png;ShortcutGuide.png;VideoConferenceMute.png ?>
<File Source="$(var.BinX64Dir)Settings\Assets\FluentIcons\FluentIcons$(var.File)" />
<?foreach File in ColorPicker.png;FancyZones.png;Espresso.png;FileExplorerPreview.png;ImageResizer.png;KeyboardManager.png;PowerRename.png;PowerToys.png;PowerToysRun.png;ShortcutGuide.png;VideoConferenceMute.png ?>
<File Id="SettingsV2OOBEAssetsFluentIcons_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\FluentIcons\FluentIcons$(var.File)" />
<?endforeach?>
</Component>
</DirectoryRef>
@ -813,6 +881,10 @@
<ComponentRef Id="Module_KeyboardManager_Engine" />
<ComponentRef Id="Module_ColorPicker" />
<ComponentRef Id="Module_ColorPicker_Resources"/>
<ComponentRef Id="Module_Espresso"/>
<ComponentRef Id="Module_Espresso_runtime_netstandard20"/>
<ComponentRef Id="Module_Espresso_runtime_netcoreapp30"/>
<ComponentRef Id="Module_Espresso_runtime_netcoreapp21"/>
<ComponentRef Id="SettingsV2" />
<ComponentRef Id="SettingsV2Assets" />
<ComponentRef Id="SettingsV2AssetsModules" />

View File

@ -8,6 +8,7 @@ namespace PTSettingsHelper
{
constexpr inline const wchar_t* log_settings_filename = L"log_settings.json";
std::wstring get_module_save_file_location(std::wstring_view powertoy_key);
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
std::wstring get_root_save_folder_location();

View File

@ -13,6 +13,7 @@ struct LogSettings
inline const static std::wstring actionRunnerLogPath = L"RunnerLogs\\action-runner-log.txt";
inline const static std::string launcherLoggerName = "launcher";
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.txt";
inline const static std::wstring espressoLogPath = L"Logs\\espresso-log.txt";
inline const static std::string fancyZonesLoggerName = "fancyzones";
inline const static std::wstring fancyZonesLogPath = L"fancyzones-log.txt";
inline const static std::wstring fancyZonesOldLogPath = L"FancyZonesLogs\\"; // needed to clean up old logs

View File

@ -0,0 +1,280 @@
// 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.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
using NLog;
namespace Espresso.Shell.Core
{
[Flags]
public enum EXECUTION_STATE : uint
{
ES_AWAYMODE_REQUIRED = 0x00000040,
ES_CONTINUOUS = 0x80000000,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_SYSTEM_REQUIRED = 0x00000001,
}
/// <summary>
/// Helper class that allows talking to Win32 APIs without having to rely on PInvoke in other parts
/// of the codebase.
/// </summary>
public class APIHelper
{
private const string BuildRegistryLocation = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion";
private const int StdOutputHandle = -11;
private const uint GenericWrite = 0x40000000;
private const uint GenericRead = 0x80000000;
private static readonly Logger _log;
private static CancellationTokenSource _tokenSource;
private static CancellationToken _threadToken;
private static Task? _runnerThread;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
[DllImport("kernel32.dll")]
private static extern uint GetCurrentThreadId();
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CreateFile(
[MarshalAs(UnmanagedType.LPTStr)] string filename,
[MarshalAs(UnmanagedType.U4)] uint access,
[MarshalAs(UnmanagedType.U4)] FileShare share,
IntPtr securityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
IntPtr templateFile);
static APIHelper()
{
_log = LogManager.GetCurrentClassLogger();
_tokenSource = new CancellationTokenSource();
}
public static void AllocateConsole()
{
_log.Debug("Bootstrapping the console allocation routine.");
AllocConsole();
_log.Debug($"Console allocation result: {Marshal.GetLastWin32Error()}");
var outputFilePointer = CreateFile("CONOUT$", GenericRead | GenericWrite, FileShare.Write, IntPtr.Zero, FileMode.OpenOrCreate, 0, IntPtr.Zero);
_log.Debug($"CONOUT creation result: {Marshal.GetLastWin32Error()}");
SetStdHandle(StdOutputHandle, outputFilePointer);
_log.Debug($"SetStdHandle result: {Marshal.GetLastWin32Error()}");
Console.SetOut(new StreamWriter(Console.OpenStandardOutput(), Console.OutputEncoding) { AutoFlush = true });
}
/// <summary>
/// Sets the computer awake state using the native Win32 SetThreadExecutionState API. This
/// function is just a nice-to-have wrapper that helps avoid tracking the success or failure of
/// the call.
/// </summary>
/// <param name="state">Single or multiple EXECUTION_STATE entries.</param>
/// <returns>true if successful, false if failed</returns>
private static bool SetAwakeState(EXECUTION_STATE state)
{
try
{
var stateResult = SetThreadExecutionState(state);
return stateResult != 0;
}
catch
{
return false;
}
}
public static void SetIndefiniteKeepAwake(Action<bool> callback, Action failureCallback, bool keepDisplayOn = false)
{
_tokenSource.Cancel();
try
{
if (_runnerThread != null && !_runnerThread.IsCanceled)
{
_runnerThread.Wait(_threadToken);
}
}
catch (OperationCanceledException)
{
_log.Info("Confirmed background thread cancellation when setting indefinite keep awake.");
}
_tokenSource = new CancellationTokenSource();
_threadToken = _tokenSource.Token;
_runnerThread = Task.Run(() => RunIndefiniteLoop(keepDisplayOn), _threadToken)
.ContinueWith((result) => callback(result.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion);
}
public static void SetNoKeepAwake()
{
_tokenSource.Cancel();
try
{
if (_runnerThread != null && !_runnerThread.IsCanceled)
{
_runnerThread.Wait(_threadToken);
}
}
catch (OperationCanceledException)
{
_log.Info("Confirmed background thread cancellation when setting passive keep awake.");
}
}
public static void SetTimedKeepAwake(uint seconds, Action<bool> callback, Action failureCallback, bool keepDisplayOn = true)
{
_tokenSource.Cancel();
try
{
if (_runnerThread != null && !_runnerThread.IsCanceled)
{
_runnerThread.Wait(_threadToken);
}
}
catch (OperationCanceledException)
{
_log.Info("Confirmed background thread cancellation when setting indefinite keep awake.");
}
_tokenSource = new CancellationTokenSource();
_threadToken = _tokenSource.Token;
_runnerThread = Task.Run(() => RunTimedLoop(seconds, keepDisplayOn), _threadToken)
.ContinueWith((result) => callback(result.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion);
}
private static bool RunIndefiniteLoop(bool keepDisplayOn = false)
{
bool success;
if (keepDisplayOn)
{
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
}
else
{
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
}
try
{
if (success)
{
_log.Info($"Initiated indefinite keep awake in background thread: {GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
while (true)
{
if (_threadToken.IsCancellationRequested)
{
_threadToken.ThrowIfCancellationRequested();
}
}
}
else
{
_log.Info("Could not successfully set up indefinite keep awake.");
return success;
}
}
catch (OperationCanceledException ex)
{
// Task was clearly cancelled.
_log.Info($"Background thread termination: {GetCurrentThreadId()}. Message: {ex.Message}");
return success;
}
}
private static bool RunTimedLoop(uint seconds, bool keepDisplayOn = true)
{
bool success = false;
// In case cancellation was already requested.
_threadToken.ThrowIfCancellationRequested();
try
{
if (keepDisplayOn)
{
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
}
else
{
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
}
if (success)
{
_log.Info($"Initiated temporary keep awake in background thread: {GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
var startTime = DateTime.UtcNow;
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(Math.Abs(seconds)))
{
if (_threadToken.IsCancellationRequested)
{
_threadToken.ThrowIfCancellationRequested();
}
}
return success;
}
else
{
_log.Info("Could not set up timed keep-awake with display on.");
return success;
}
}
catch (OperationCanceledException ex)
{
// Task was clearly cancelled.
_log.Info($"Background thread termination: {GetCurrentThreadId()}. Message: {ex.Message}");
return success;
}
}
public static string GetOperatingSystemBuild()
{
try
{
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BuildRegistryLocation);
#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type.
if (registryKey != null)
{
var versionString = $"{registryKey.GetValue("ProductName")} {registryKey.GetValue("DisplayVersion")} {registryKey.GetValue("BuildLabEx")}";
return versionString;
}
else
{
_log.Info("Registry key acquisition for OS failed.");
return string.Empty;
}
}
catch (Exception ex)
{
_log.Info($"Could not get registry key for the build number. Error: {ex.Message}");
return string.Empty;
}
}
}
}

View File

@ -0,0 +1,297 @@
// 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.Drawing;
using System.IO;
using System.Text.Json;
using System.Windows.Forms;
using Microsoft.PowerToys.Settings.UI.Library;
#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8603 // Possible null reference return.
namespace Espresso.Shell.Core
{
internal static class TrayHelper
{
private static NotifyIcon? trayIcon;
private static NotifyIcon TrayIcon { get => trayIcon; set => trayIcon = value; }
private static SettingsUtils? moduleSettings;
private static SettingsUtils ModuleSettings { get => moduleSettings; set => moduleSettings = value; }
static TrayHelper()
{
TrayIcon = new NotifyIcon();
ModuleSettings = new SettingsUtils();
}
public static void InitializeTray(string text, Icon icon, ContextMenuStrip? contextMenu = null)
{
System.Threading.Tasks.Task.Factory.StartNew(
(tray) =>
{
((NotifyIcon?)tray).Text = text;
((NotifyIcon?)tray).Icon = icon;
((NotifyIcon?)tray).ContextMenuStrip = contextMenu;
((NotifyIcon?)tray).Visible = true;
Application.Run();
}, TrayIcon);
}
internal static void SetTray(string text, EspressoSettings settings)
{
SetTray(
text,
settings.Properties.KeepDisplayOn,
settings.Properties.Mode,
PassiveKeepAwakeCallback(text),
IndefiniteKeepAwakeCallback(text),
TimedKeepAwakeCallback(text),
KeepDisplayOnCallback(text),
ExitCallback());
}
private static Action ExitCallback()
{
return () =>
{
Environment.Exit(0);
};
}
private static Action KeepDisplayOnCallback(string moduleName)
{
return () =>
{
EspressoSettings currentSettings;
try
{
currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
}
catch (FileNotFoundException)
{
currentSettings = new EspressoSettings();
}
currentSettings.Properties.KeepDisplayOn = !currentSettings.Properties.KeepDisplayOn;
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
};
}
private static Action<uint, uint> TimedKeepAwakeCallback(string moduleName)
{
return (hours, minutes) =>
{
EspressoSettings currentSettings;
try
{
currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
}
catch (FileNotFoundException)
{
currentSettings = new EspressoSettings();
}
currentSettings.Properties.Mode = EspressoMode.TIMED;
currentSettings.Properties.Hours = hours;
currentSettings.Properties.Minutes = minutes;
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
};
}
private static Action PassiveKeepAwakeCallback(string moduleName)
{
return () =>
{
EspressoSettings currentSettings;
try
{
currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
}
catch (FileNotFoundException)
{
currentSettings = new EspressoSettings();
}
currentSettings.Properties.Mode = EspressoMode.PASSIVE;
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
};
}
private static Action IndefiniteKeepAwakeCallback(string moduleName)
{
return () =>
{
EspressoSettings currentSettings;
try
{
currentSettings = ModuleSettings.GetSettings<EspressoSettings>(moduleName);
}
catch (FileNotFoundException)
{
currentSettings = new EspressoSettings();
}
currentSettings.Properties.Mode = EspressoMode.INDEFINITE;
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName);
};
}
public static void SetTray(string text, bool keepDisplayOn, EspressoMode mode, Action passiveKeepAwakeCallback, Action indefiniteKeepAwakeCallback, Action<uint, uint> timedKeepAwakeCallback, Action keepDisplayOnCallback, Action exitCallback)
{
var contextMenuStrip = new ContextMenuStrip();
// Main toolstrip.
var operationContextMenu = new ToolStripMenuItem
{
Text = "Mode",
};
// No keep-awake menu item.
var passiveMenuItem = new ToolStripMenuItem
{
Text = "Off (Passive)",
};
if (mode == EspressoMode.PASSIVE)
{
passiveMenuItem.Checked = true;
}
else
{
passiveMenuItem.Checked = false;
}
passiveMenuItem.Click += (e, s) =>
{
// User opted to set the mode to indefinite, so we need to write new settings.
passiveKeepAwakeCallback();
};
// Indefinite keep-awake menu item.
var indefiniteMenuItem = new ToolStripMenuItem
{
Text = "Keep awake indefinitely",
};
if (mode == EspressoMode.INDEFINITE)
{
indefiniteMenuItem.Checked = true;
}
else
{
indefiniteMenuItem.Checked = false;
}
indefiniteMenuItem.Click += (e, s) =>
{
// User opted to set the mode to indefinite, so we need to write new settings.
indefiniteKeepAwakeCallback();
};
var displayOnMenuItem = new ToolStripMenuItem
{
Text = "Keep screen on",
};
if (keepDisplayOn)
{
displayOnMenuItem.Checked = true;
}
else
{
displayOnMenuItem.Checked = false;
}
displayOnMenuItem.Click += (e, s) =>
{
// User opted to set the display mode directly.
keepDisplayOnCallback();
};
// Timed keep-awake menu item
var timedMenuItem = new ToolStripMenuItem
{
Text = "Keep awake temporarily",
};
if (mode == EspressoMode.TIMED)
{
timedMenuItem.Checked = true;
}
else
{
timedMenuItem.Checked = false;
}
var halfHourMenuItem = new ToolStripMenuItem
{
Text = "30 minutes",
};
halfHourMenuItem.Click += (e, s) =>
{
// User is setting the keep-awake to 30 minutes.
timedKeepAwakeCallback(0, 30);
};
var oneHourMenuItem = new ToolStripMenuItem
{
Text = "1 hour",
};
oneHourMenuItem.Click += (e, s) =>
{
// User is setting the keep-awake to 1 hour.
timedKeepAwakeCallback(1, 0);
};
var twoHoursMenuItem = new ToolStripMenuItem
{
Text = "2 hours",
};
twoHoursMenuItem.Click += (e, s) =>
{
// User is setting the keep-awake to 2 hours.
timedKeepAwakeCallback(2, 0);
};
// Exit menu item.
var exitContextMenu = new ToolStripMenuItem
{
Text = "Exit",
};
exitContextMenu.Click += (e, s) =>
{
// User is setting the keep-awake to 2 hours.
exitCallback();
};
timedMenuItem.DropDownItems.Add(halfHourMenuItem);
timedMenuItem.DropDownItems.Add(oneHourMenuItem);
timedMenuItem.DropDownItems.Add(twoHoursMenuItem);
operationContextMenu.DropDownItems.Add(passiveMenuItem);
operationContextMenu.DropDownItems.Add(indefiniteMenuItem);
operationContextMenu.DropDownItems.Add(timedMenuItem);
contextMenuStrip.Items.Add(operationContextMenu);
contextMenuStrip.Items.Add(displayOnMenuItem);
contextMenuStrip.Items.Add(new ToolStripSeparator());
contextMenuStrip.Items.Add(exitContextMenu);
TrayIcon.Text = text;
TrayIcon.ContextMenuStrip = contextMenuStrip;
}
}
}

View File

@ -0,0 +1,83 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\modules\Espresso</OutputPath>
<Nullable>enable</Nullable>
<Platforms>x64</Platforms>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<UseWindowsForms>true</UseWindowsForms>
<!--Per documentation: https://docs.microsoft.com/dotnet/core/compatibility/windows-forms/5.0/automatically-infer-winexe-output-type#outputtype-set-to-winexe-for-wpf-and-winforms-apps -->
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
<AssemblyName>PowerToys.Espresso</AssemblyName>
<Version>$(Version).0</Version>
<ApplicationIcon>Images\Espresso.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DefineConstants>TRACE;RELEASE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="NLog" Version="4.7.9" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20071.2" />
<PackageReference Include="System.Reactive" Version="5.0.0" />
<PackageReference Include="System.Runtime.Caching" Version="6.0.0-preview.1.21102.12" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\settings-ui\Microsoft.PowerToys.Settings.UI.Library\Microsoft.PowerToys.Settings.UI.Library.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Program.cs">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="NLog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs">
<Link>GlobalSuppressions.cs</Link>
</Compile>
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
<Link>StyleCop.json</Link>
</AdditionalFiles>
</ItemGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers">
<Version>1.1.118</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Resource Include="Images\Espresso.ico" />
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<variable name="espressoversion" value="0.0.1" />
<targets async="true">
<target name="logfile"
xsi:type="File"
fileName="${specialfolder:folder=LocalApplicationData}/Microsoft/PowerToys/Espresso/Logs/${var:espressoversion}/log_${date:format=yyyy-MM-dd_HH}_DBG.txt"
layout="[${longdate} ${level:uppercase=true} ${logger}] ${message}"
archiveEvery="Day"
archiveNumbering="Rolling"
maxArchiveFiles="30"/>
<target name="logconsole" xsi:type="Console" layout="[${longdate} ${level:uppercase=true}] ${message}" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="logconsole" />
<logger name="*" minlevel="Debug" writeTo="logfile" />
</rules>
</nlog>

View File

@ -0,0 +1,320 @@
// 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.CommandLine;
using System.CommandLine.Invocation;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reflection;
using System.Threading;
using System.Windows;
using Espresso.Shell.Core;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using NLog;
#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8603 // Possible null reference return.
namespace Espresso.Shell
{
internal class Program
{
private static Mutex? _mutex = null;
private const string AppName = "Espresso";
private static FileSystemWatcher? _watcher = null;
private static SettingsUtils? _settingsUtils = null;
public static Mutex LockMutex { get => _mutex; set => _mutex = value; }
private static Logger? _log;
private static int Main(string[] args)
{
bool instantiated;
LockMutex = new Mutex(true, AppName, out instantiated);
if (!instantiated)
{
ForceExit(AppName + " is already running! Exiting the application.", 1);
}
_log = LogManager.GetCurrentClassLogger();
_settingsUtils = new SettingsUtils();
_log.Info("Launching Espresso...");
_log.Info(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion);
_log.Info($"OS: {Environment.OSVersion}");
_log.Info($"OS Build: {APIHelper.GetOperatingSystemBuild()}");
_log.Info("Parsing parameters...");
var configOption = new Option<bool>(
aliases: new[] { "--use-pt-config", "-c" },
getDefaultValue: () => false,
description: "Specifies whether Espresso will be using the PowerToys configuration file for managing the state.")
{
Argument = new Argument<bool>(() => false)
{
Arity = ArgumentArity.ZeroOrOne,
},
};
configOption.Required = false;
var displayOption = new Option<bool>(
aliases: new[] { "--display-on", "-d" },
getDefaultValue: () => true,
description: "Determines whether the display should be kept awake.")
{
Argument = new Argument<bool>(() => false)
{
Arity = ArgumentArity.ZeroOrOne,
},
};
displayOption.Required = false;
var timeOption = new Option<uint>(
aliases: new[] { "--time-limit", "-t" },
getDefaultValue: () => 0,
description: "Determines the interval, in seconds, during which the computer is kept awake.")
{
Argument = new Argument<uint>(() => 0)
{
Arity = ArgumentArity.ExactlyOne,
},
};
timeOption.Required = false;
var pidOption = new Option<int>(
aliases: new[] { "--pid", "-p" },
getDefaultValue: () => 0,
description: "Bind the execution of Espresso to another process.")
{
Argument = new Argument<int>(() => 0)
{
Arity = ArgumentArity.ZeroOrOne,
},
};
pidOption.Required = false;
var rootCommand = new RootCommand
{
configOption,
displayOption,
timeOption,
pidOption,
};
rootCommand.Description = AppName;
rootCommand.Handler = CommandHandler.Create<bool, bool, uint, int>(HandleCommandLineArguments);
_log.Info("Parameter setup complete. Proceeding to the rest of the app initiation...");
return rootCommand.InvokeAsync(args).Result;
}
private static void ForceExit(string message, int exitCode)
{
_log.Info(message);
Console.ReadKey();
Environment.Exit(exitCode);
}
private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, uint timeLimit, int pid)
{
if (pid == 0)
{
_log.Info("No PID specified. Allocating console...");
APIHelper.AllocateConsole();
}
_log.Info($"The value for --use-pt-config is: {usePtConfig}");
_log.Info($"The value for --display-on is: {displayOn}");
_log.Info($"The value for --time-limit is: {timeLimit}");
_log.Info($"The value for --pid is: {pid}");
if (usePtConfig)
{
// Configuration file is used, therefore we disregard any other command-line parameter
// and instead watch for changes in the file.
try
{
#pragma warning disable CS8604 // Possible null reference argument.
TrayHelper.InitializeTray(AppName, new Icon(Application.GetResourceStream(new Uri("/Images/Espresso.ico", UriKind.Relative)).Stream));
#pragma warning restore CS8604 // Possible null reference argument.
var settingsPath = _settingsUtils.GetSettingsFilePath(AppName);
_log.Info($"Reading configuration file: {settingsPath}");
_watcher = new FileSystemWatcher
{
Path = Path.GetDirectoryName(settingsPath),
EnableRaisingEvents = true,
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime,
Filter = Path.GetFileName(settingsPath),
};
var changedObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
h => _watcher.Changed += h,
h => _watcher.Changed -= h);
var createdObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
cre => _watcher.Created += cre,
cre => _watcher.Created -= cre);
var mergedObservable = Observable.Merge(changedObservable, createdObservable);
mergedObservable.Throttle(TimeSpan.FromMilliseconds(25))
.SubscribeOn(TaskPoolScheduler.Default)
.Select(e => e.EventArgs)
.Subscribe(HandleEspressoConfigChange);
TrayHelper.SetTray(AppName, new EspressoSettings());
// Initially the file might not be updated, so we need to start processing
// settings right away.
ProcessSettings();
}
catch (Exception ex)
{
var errorString = $"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}";
_log.Info(errorString);
_log.Debug(errorString);
}
}
else
{
var mode = timeLimit <= 0 ? EspressoMode.INDEFINITE : EspressoMode.TIMED;
if (mode == EspressoMode.INDEFINITE)
{
SetupIndefiniteKeepAwake(displayOn);
}
else
{
SetupTimedKeepAwake(timeLimit, displayOn);
}
}
var exitSignal = new ManualResetEvent(false);
if (pid != 0)
{
RunnerHelper.WaitForPowerToysRunner(pid, () =>
{
exitSignal.Set();
Environment.Exit(0);
});
}
exitSignal.WaitOne();
}
private static void SetupIndefiniteKeepAwake(bool displayOn)
{
// Indefinite keep awake.
APIHelper.SetIndefiniteKeepAwake(LogCompletedKeepAwakeThread, LogUnexpectedOrCancelledKeepAwakeThreadCompletion, displayOn);
}
private static void HandleEspressoConfigChange(FileSystemEventArgs fileEvent)
{
_log.Info("Detected a settings file change. Updating configuration...");
_log.Info("Resetting keep-awake to normal state due to settings change.");
ProcessSettings();
}
private static void ProcessSettings()
{
try
{
EspressoSettings settings = _settingsUtils.GetSettings<EspressoSettings>(AppName);
if (settings != null)
{
switch (settings.Properties.Mode)
{
case EspressoMode.PASSIVE:
{
SetupNoKeepAwake();
break;
}
case EspressoMode.INDEFINITE:
{
// Indefinite keep awake.
SetupIndefiniteKeepAwake(settings.Properties.KeepDisplayOn);
break;
}
case EspressoMode.TIMED:
{
// Timed keep-awake.
uint computedTime = (settings.Properties.Hours * 60 * 60) + (settings.Properties.Minutes * 60);
SetupTimedKeepAwake(computedTime, settings.Properties.KeepDisplayOn);
break;
}
default:
{
var errorMessage = "Unknown mode of operation. Check config file.";
_log.Info(errorMessage);
_log.Debug(errorMessage);
break;
}
}
TrayHelper.SetTray(AppName, settings);
}
else
{
var errorMessage = "Settings are null.";
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
}
catch (Exception ex)
{
var errorMessage = $"There was a problem reading the configuration file. Error: {ex.GetType()} {ex.Message}";
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
}
private static void SetupNoKeepAwake()
{
_log.Info($"Operating in passive mode (computer's standard power plan). No custom keep awake settings enabled.");
APIHelper.SetNoKeepAwake();
}
private static void SetupTimedKeepAwake(uint time, bool displayOn)
{
_log.Info($"Timed keep-awake. Expected runtime: {time} seconds with display on setting set to {displayOn}.");
APIHelper.SetTimedKeepAwake(time, LogCompletedKeepAwakeThread, LogUnexpectedOrCancelledKeepAwakeThreadCompletion, displayOn);
}
private static void LogUnexpectedOrCancelledKeepAwakeThreadCompletion()
{
var errorMessage = "The keep-awake thread was terminated early.";
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
private static void LogCompletedKeepAwakeThread(bool result)
{
_log.Info($"Exited keep-awake thread successfully: {result}");
}
}
}

View File

@ -0,0 +1,7 @@
#include <string>
namespace EspressoConstants
{
// Name of the powertoy module.
inline const std::wstring ModuleKey = L"Espresso";
}

View File

@ -0,0 +1,72 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_ESPRESSO_NAME "Espresso"
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{5e7360a8-d048-4ed3-8f09-0bfd64c5529a}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Espresso</RootNamespace>
<ProjectName>EspressoModuleInterface</ProjectName>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\Espresso\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="EspressoConstants.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="trace.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="EspressoModuleInterface.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="trace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EspressoConstants.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Generated Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{e8ef1c4e-cc50-4ce5-b00d-4e3ac5c1a7db}</UniqueIdentifier>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{fbd9cdd2-e7d5-4417-9b52-25e345ae9562}</UniqueIdentifier>
</Filter>
<Filter Include="Generated Files">
<UniqueIdentifier>{c2a23a2b-5846-440f-b29e-eea748dba12d}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{77f1702b-da7f-4ff6-90a3-19db515cf963}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="EspressoModuleInterface.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,181 @@
#include "pch.h"
#include <interface/powertoy_module_interface.h>
#include <common/SettingsAPI/settings_objects.h>
#include <common/interop/shared_constants.h>
#include "trace.h"
#include "resource.h"
#include "EspressoConstants.h"
#include <common/logger/logger.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/utils/elevation.h>
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
#include <common/utils/os-detect.h>
#include <common/utils/winapi_error.h>
#include <filesystem>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Trace::RegisterProvider();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Trace::UnregisterProvider();
break;
}
return TRUE;
}
// The PowerToy name that will be shown in the settings.
const static wchar_t* MODULE_NAME = L"Espresso";
// Add a description that will we shown in the module settings page.
const static wchar_t* MODULE_DESC = L"<no description>";
// Implement the PowerToy Module Interface and all the required methods.
class Espresso : public PowertoyModuleIface
{
std::wstring app_name;
// Contains the non localized key of the powertoy
std::wstring app_key;
private:
// The PowerToy state.
bool m_enabled = false;
HANDLE m_hProcess;
HANDLE send_telemetry_event;
// Handle to event used to invoke Espresso
HANDLE m_hInvokeEvent;
bool is_process_running()
{
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
}
void launch_process()
{
Logger::trace(L"Launching Espresso process");
unsigned long powertoys_pid = GetCurrentProcessId();
std::wstring executable_args = L"--use-pt-config --pid " + std::to_wstring(powertoys_pid);
Logger::trace(L"Espresso launching with parameters: " + executable_args);
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
sei.lpFile = L"modules\\Espresso\\PowerToys.Espresso.exe";
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = executable_args.data();
if (!ShellExecuteExW(&sei))
{
DWORD error = GetLastError();
std::wstring message = L"Espresso failed to start with error = ";
message += std::to_wstring(error);
Logger::error(message);
}
m_hProcess = sei.hProcess;
}
public:
// Constructor
Espresso()
{
app_name = GET_RESOURCE_STRING(IDS_ESPRESSO_NAME);
app_key = EspressoConstants::ModuleKey;
std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(this->app_key));
logFilePath.append(LogSettings::espressoLogPath);
Logger::init(LogSettings::launcherLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
Logger::info("Launcher object is constructing");
};
// Destroy the powertoy and free memory
virtual void destroy() override
{
delete this;
}
// Return the display name of the powertoy, this will be cached by the runner
virtual const wchar_t* get_name() override
{
return MODULE_NAME;
}
// Return JSON with the configuration options.
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
{
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
// Create a Settings object.
PowerToysSettings::Settings settings(hinstance, get_name());
settings.set_description(MODULE_DESC);
return settings.serialize_to_buffer(buffer, buffer_size);
}
// Return the non localized key of the powertoy, this will be cached by the runner
virtual const wchar_t* get_key() override
{
return app_key.c_str();
}
// Called by the runner to pass the updated settings values as a serialized JSON.
virtual void set_config(const wchar_t* config) override
{
try
{
// Parse the input JSON string.
PowerToysSettings::PowerToyValues values =
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
// If you don't need to do any custom processing of the settings, proceed
// to persists the values calling:
values.save_to_settings_file();
}
catch (std::exception&)
{
// Improper JSON.
}
}
virtual void enable()
{
ResetEvent(send_telemetry_event);
ResetEvent(m_hInvokeEvent);
launch_process();
m_enabled = true;
};
virtual void disable()
{
if (m_enabled)
{
ResetEvent(send_telemetry_event);
ResetEvent(m_hInvokeEvent);
TerminateProcess(m_hProcess, 1);
}
m_enabled = false;
}
// Returns if the powertoys is enabled
virtual bool is_enabled() override
{
return m_enabled;
}
};
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new Espresso();
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
</packages>

View File

@ -0,0 +1 @@
#include "pch.h"

View File

@ -0,0 +1,7 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <ProjectTelemetry.h>
#include <shellapi.h>
#include <Shlwapi.h>

View File

@ -0,0 +1,16 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Espresso.rc
//
#define IDS_ESPRESSO_NAME 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -0,0 +1,19 @@
#include "pch.h"
#include "trace.h"
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
"Microsoft.PowerToys",
// {38e8889b-9731-53f5-e901-e8a7c1753074}
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry());
void Trace::RegisterProvider()
{
TraceLoggingRegister(g_hProvider);
}
void Trace::UnregisterProvider()
{
TraceLoggingUnregister(g_hProvider);
}

View File

@ -0,0 +1,8 @@
#pragma once
class Trace
{
public:
static void RegisterProvider();
static void UnregisterProvider();
};

View File

@ -149,7 +149,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
chdir_current_executable();
// Load Powertoys DLLs
const std::array<std::wstring_view, 8> knownModules = {
const std::array<std::wstring_view, 9> knownModules = {
L"modules/FancyZones/fancyzones.dll",
L"modules/FileExplorerPreview/powerpreview.dll",
L"modules/ImageResizer/ImageResizerExt.dll",
@ -158,6 +158,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
L"modules/PowerRename/PowerRenameExt.dll",
L"modules/ShortcutGuide/ShortcutGuideModuleInterface/ShortcutGuideModuleInterface.dll",
L"modules/ColorPicker/ColorPicker.dll",
L"modules/Espresso/EspressoModuleInterface.dll",
};
for (const auto& moduleSubdir : knownModules)

View File

@ -143,6 +143,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
}
}
private bool espresso;
[JsonPropertyName("Espresso")]
public bool Espresso
{
get => espresso;
set
{
if (espresso != value)
{
LogTelemetryEvent(value);
espresso = value;
}
}
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this);

View File

@ -0,0 +1,38 @@
// 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.Serialization;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class EspressoProperties
{
public EspressoProperties()
{
KeepDisplayOn = false;
Mode = EspressoMode.PASSIVE;
Hours = 0;
Minutes = 0;
}
[JsonPropertyName("espresso_keep_display_on")]
public bool KeepDisplayOn { get; set; }
[JsonPropertyName("espresso_mode")]
public EspressoMode Mode { get; set; }
[JsonPropertyName("espresso_hours")]
public uint Hours { get; set; }
[JsonPropertyName("espresso_minutes")]
public uint Minutes { get; set; }
}
public enum EspressoMode
{
PASSIVE = 0,
INDEFINITE = 1,
TIMED = 2,
}
}

View File

@ -0,0 +1,35 @@
// 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.Serialization;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class EspressoSettings : BasePTModuleSettings, ISettingsConfig
{
public const string ModuleName = "Espresso";
public const string ModuleVersion = "0.0.1";
public EspressoSettings()
{
Name = ModuleName;
Version = ModuleVersion;
Properties = new EspressoProperties();
}
[JsonPropertyName("properties")]
public EspressoProperties Properties { get; set; }
public string GetModuleName()
{
return Name;
}
public bool UpgradeSettingsConfiguration()
{
return false;
}
}
}

View File

@ -19,5 +19,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
bool SettingsExists(string powertoy = "", string fileName = "settings.json");
void DeleteSettings(string powertoy = "");
string GetSettingsFilePath(string powertoy = "", string fileName = "settings.json");
}
}

View File

@ -20,6 +20,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

View File

@ -135,5 +135,11 @@ namespace Microsoft.PowerToys.Settings.UI.Library
#endif
}
}
// Returns the file path to the settings file, that is exposed from the local ISettingsPath instance.
public string GetSettingsFilePath(string powertoy = "", string fileName = "settings.json")
{
return _settingsPath.GetSettingsPath(powertoy, fileName);
}
}
}

View File

@ -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 System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class SndEspressoSettings
{
[JsonPropertyName("Espresso")]
public EspressoSettings Settings { get; set; }
public SndEspressoSettings()
{
}
public SndEspressoSettings(EspressoSettings settings)
{
Settings = settings;
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
}
}
}

View File

@ -0,0 +1,157 @@
// 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.Runtime.CompilerServices;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
{
public class EspressoViewModel : Observable
{
private GeneralSettings GeneralSettingsConfig { get; set; }
private EspressoSettings Settings { get; set; }
private Func<string, int> SendConfigMSG { get; }
public EspressoViewModel(ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<EspressoSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc)
{
// To obtain the general settings configurations of PowerToys Settings.
if (settingsRepository == null)
{
throw new ArgumentNullException(nameof(settingsRepository));
}
GeneralSettingsConfig = settingsRepository.SettingsConfig;
// To obtain the settings configurations of Fancy zones.
if (moduleSettingsRepository == null)
{
throw new ArgumentNullException(nameof(moduleSettingsRepository));
}
Settings = moduleSettingsRepository.SettingsConfig;
_isEnabled = GeneralSettingsConfig.Enabled.Espresso;
_keepDisplayOn = Settings.Properties.KeepDisplayOn;
_mode = Settings.Properties.Mode;
_hours = Settings.Properties.Hours;
_minutes = Settings.Properties.Minutes;
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
}
public bool IsEnabled
{
get => _isEnabled;
set
{
if (_isEnabled != value)
{
_isEnabled = value;
GeneralSettingsConfig.Enabled.Espresso = value;
OnPropertyChanged(nameof(IsEnabled));
OnPropertyChanged(nameof(IsTimeConfigurationEnabled));
var outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(outgoing.ToString());
NotifyPropertyChanged();
}
}
}
public bool IsTimeConfigurationEnabled
{
get => _mode == EspressoMode.TIMED && _isEnabled;
}
public EspressoMode Mode
{
get => _mode;
set
{
if (_mode != value)
{
_mode = value;
OnPropertyChanged(nameof(Mode));
OnPropertyChanged(nameof(IsTimeConfigurationEnabled));
Settings.Properties.Mode = value;
NotifyPropertyChanged();
}
}
}
public bool KeepDisplayOn
{
get => _keepDisplayOn;
set
{
if (_keepDisplayOn != value)
{
_keepDisplayOn = value;
OnPropertyChanged(nameof(KeepDisplayOn));
Settings.Properties.KeepDisplayOn = value;
NotifyPropertyChanged();
}
}
}
public uint Hours
{
get => _hours;
set
{
if (_hours != value)
{
_hours = value;
OnPropertyChanged(nameof(Hours));
Settings.Properties.Hours = value;
NotifyPropertyChanged();
}
}
}
public uint Minutes
{
get => _minutes;
set
{
if (_minutes != value)
{
_minutes = value;
OnPropertyChanged(nameof(Minutes));
Settings.Properties.Minutes = value;
NotifyPropertyChanged();
}
}
}
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
OnPropertyChanged(propertyName);
if (SendConfigMSG != null)
{
SndEspressoSettings outsettings = new SndEspressoSettings(Settings);
SndModuleSettings<SndEspressoSettings> ipcMessage = new SndModuleSettings<SndEspressoSettings>(outsettings);
var targetMessage = ipcMessage.ToJsonString();
SendConfigMSG(targetMessage);
}
}
private bool _isEnabled;
private uint _hours;
private uint _minutes;
private bool _keepDisplayOn;
private EspressoMode _mode;
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
@ -9,6 +9,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutputPath>..\..\..\x64\Debug\SettingsTests\</OutputPath>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

View File

@ -0,0 +1,41 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using Windows.UI.Xaml.Data;
namespace Microsoft.PowerToys.Settings.UI.Converters
{
public sealed class EspressoModeToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (targetType != typeof(bool?))
{
throw new InvalidOperationException("The target type needs to be a boolean.");
}
if (parameter == null)
{
throw new NullReferenceException("Parameter cannot be null for the Espresso mode to bool converter.");
}
var expectedMode = (EspressoMode)Enum.Parse(typeof(EspressoMode), parameter.ToString());
var currentMode = (EspressoMode)value;
return currentMode.Equals(expectedMode);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (parameter == null)
{
throw new NullReferenceException("Parameter cannot be null for the Espresso mode to bool converter.");
}
return (EspressoMode)Enum.Parse(typeof(EspressoMode), parameter.ToString());
}
}
}

View File

@ -105,6 +105,7 @@
<Compile Include="Controls\ShortcutVisualControl.xaml.cs">
<DependentUpon>ShortcutVisualControl.xaml</DependentUpon>
</Compile>
<Compile Include="Converters\EspressoModeToBoolConverter.cs" />
<Compile Include="Converters\ModuleEnabledToForegroundConverter.cs" />
<Compile Include="Converters\UpdatingStateCannotDownloadToVisibilityConverter.cs" />
<Compile Include="Converters\UpdatingStateReadyToDownloadToVisibilityConverter.cs" />
@ -125,6 +126,9 @@
<Compile Include="OOBE\Enums\PowerToysModulesEnum.cs" />
<Compile Include="OOBE\ViewModel\OobeShellViewModel.cs" />
<Compile Include="OOBE\ViewModel\OobePowerToysModule.cs" />
<Compile Include="OOBE\Views\OobeEspresso.xaml.cs">
<DependentUpon>OobeEspresso.xaml</DependentUpon>
</Compile>
<Compile Include="OOBE\Views\OobeColorPicker.xaml.cs">
<DependentUpon>OobeColorPicker.xaml</DependentUpon>
</Compile>
@ -162,6 +166,9 @@
<Compile Include="Services\NavigationService.cs" />
<Compile Include="ViewModels\Commands\ButtonClickCommand.cs" />
<Compile Include="ViewModels\ShellViewModel.cs" />
<Compile Include="Views\EspressoPage.xaml.cs">
<DependentUpon>EspressoPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ColorPickerPage.xaml.cs">
<DependentUpon>ColorPickerPage.xaml</DependentUpon>
</Compile>
@ -201,6 +208,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="Assets\FluentIcons\FluentIconsColorPicker.png" />
<Content Include="Assets\FluentIcons\FluentIconsEspresso.png" />
<Content Include="Assets\FluentIcons\FluentIconsFancyZones.png" />
<Content Include="Assets\FluentIcons\FluentIconsFileExplorerPreview.png" />
<Content Include="Assets\FluentIcons\FluentIconsImageResizer.png" />
@ -212,10 +220,12 @@
<Content Include="Assets\FluentIcons\FluentIconsVideoConferenceMute.png" />
<Content Include="Assets\Logo.scale-200.png" />
<Content Include="Assets\Modules\ColorPicker.png" />
<Content Include="Assets\Modules\Espresso.png" />
<Content Include="Assets\Modules\FancyZones.png" />
<Content Include="Assets\Modules\ImageResizer.png" />
<Content Include="Assets\Modules\KBM.png" />
<Content Include="Assets\Modules\OOBE\ColorPicker.gif" />
<Content Include="Assets\Modules\OOBE\Espresso.png" />
<Content Include="Assets\Modules\OOBE\FancyZones.gif" />
<Content Include="Assets\Modules\OOBE\FileExplorer.png" />
<Content Include="Assets\Modules\OOBE\ImageResizer.gif" />
@ -298,6 +308,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="OOBE\Views\OobeEspresso.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="OOBE\Views\OobeColorPicker.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -370,6 +384,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\EspressoPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\ColorPickerPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -448,4 +466,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@ -8,6 +8,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Enums
{
Overview = 0,
ColorPicker,
Espresso,
FancyZones,
FileExplorer,
ImageResizer,

View File

@ -0,0 +1,70 @@
<Page x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobeEspresso"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.PowerToys.Settings.UI.OOBE.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="280" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Stretch="UniformToFill"
Source="{x:Bind ViewModel.PreviewImageSource}" />
<ScrollViewer Grid.Row="1"
VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical"
Margin="{StaticResource OobePageContentMargin}"
VerticalAlignment="Top">
<TextBlock Text="{x:Bind ViewModel.ModuleName}"
AutomationProperties.HeadingLevel="Level2"
Style="{StaticResource PageTitleStyle}" />
<TextBlock TextWrapping="Wrap"
Margin="0,4,0,0"
Text="{x:Bind ViewModel.Description}" />
<HyperlinkButton NavigateUri="{x:Bind ViewModel.Link}" Margin="0,0,0,4">
<TextBlock>
<Run x:Uid="Oobe_LearnMore" />
<Run Text="{x:Bind ViewModel.ModuleName}" />
</TextBlock>
</HyperlinkButton>
<TextBlock x:Uid="Oobe_HowToUse"
AutomationProperties.HeadingLevel="Level3"
Style="{StaticResource OobeSubtitleStyle}" />
<controls:ShortcutTextControl x:Uid="Oobe_Espresso_HowToUse" />
<TextBlock x:Uid="Oobe_TipsAndTricks"
AutomationProperties.HeadingLevel="Level3"
Style="{StaticResource OobeSubtitleStyle}"/>
<controls:ShortcutTextControl x:Uid="Oobe_Espresso_TipsAndTricks" />
<StackPanel Orientation="Horizontal"
Spacing="4"
Margin="0,32,0,0">
<Button Click="SettingsLaunchButton_Click"
AutomationProperties.LabeledBy="{Binding ElementName=SettingsLabel}">
<StackPanel Orientation="Horizontal"
Spacing="8">
<TextBlock Text="&#xE115;"
Margin="0,3,0,0"
FontFamily="Segoe MDL2 Assets" />
<TextBlock x:Uid="OOBE_Settings" Name="SettingsLabel" />
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

View File

@ -0,0 +1,48 @@
// 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;
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
using Microsoft.PowerToys.Settings.UI.Views;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class OobeEspresso : Page
{
public OobePowerToysModule ViewModel { get; set; }
public OobeEspresso()
{
this.InitializeComponent();
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.Espresso]);
DataContext = ViewModel;
}
private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if (OobeShellPage.OpenMainWindowCallback != null)
{
OobeShellPage.OpenMainWindowCallback(typeof(EspressoPage));
}
ViewModel.LogOpeningSettingsEvent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
ViewModel.LogOpeningModuleEvent();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
ViewModel.LogClosingModuleEvent();
}
}
}

View File

@ -81,6 +81,18 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
Description = loader.GetString("Oobe_ColorPicker_Description"),
Link = "https://aka.ms/PowerToysOverview_ColorPicker",
});
Modules.Insert((int)PowerToysModulesEnum.Espresso, new OobePowerToysModule()
{
ModuleName = loader.GetString("Oobe_Espresso"),
Tag = "Espresso",
IsNew = false,
Icon = "\uEC32",
Image = "ms-appx:///Assets/Modules/Espresso.png",
FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsEspresso.png",
PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/Espresso.png",
Description = loader.GetString("Oobe_Espresso_Description"),
Link = "https://aka.ms/PowerToysOverview_Espresso",
});
Modules.Insert((int)PowerToysModulesEnum.FancyZones, new OobePowerToysModule()
{
ModuleName = loader.GetString("Oobe_FancyZones"),
@ -204,6 +216,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
{
case "Overview": NavigationFrame.Navigate(typeof(OobeOverview)); break;
case "ColorPicker": NavigationFrame.Navigate(typeof(OobeColorPicker)); break;
case "Espresso": NavigationFrame.Navigate(typeof(OobeEspresso)); break;
case "FancyZones": NavigationFrame.Navigate(typeof(OobeFancyZones)); break;
case "Run": NavigationFrame.Navigate(typeof(OobeRun)); break;
case "ImageResizer": NavigationFrame.Navigate(typeof(OobeImageResizer)); break;

View File

@ -121,6 +121,10 @@
<value>General</value>
<comment>Navigation view item name for General</comment>
</data>
<data name="Shell_Espresso.Content" xml:space="preserve">
<value>Espresso</value>
<comment>Product name: Navigation view item name for Espresso</comment>
</data>
<data name="Shell_PowerLauncher.Content" xml:space="preserve">
<value>PowerToys Run</value>
<comment>Product name: Navigation view item name for PowerToys Run</comment>
@ -480,6 +484,10 @@
<data name="ShortcutGuide_Description.Text" xml:space="preserve">
<value>Shows a help overlay with Windows shortcuts when the Windows key is pressed.</value>
</data>
<data name="ShortcutGuide_PressTime.Header" xml:space="preserve">
<value>Press duration before showing (ms)</value>
<comment>pressing a key in milliseconds</comment>
</data>
<data name="ShortcutGuide_Appearance_Behavior.Text" xml:space="preserve">
<value>Appearance &amp; behavior</value>
</data>
@ -904,6 +912,10 @@
<value>https://aka.ms/PowerToysOverview_ColorPicker</value>
<comment>URL. Do not loc</comment>
</data>
<data name="Espresso_ImageHyperlinkToDocs.NavigateUri" xml:space="preserve">
<value>https://aka.ms/PowerToysOverview_Espresso</value>
<comment>URL. Do not loc</comment>
</data>
<data name="FancyZones_ImageHyperlinkToDocs.NavigateUri" xml:space="preserve">
<value>https://aka.ms/PowerToysOverview_FancyZones</value>
<comment>URL. Do not loc</comment>
@ -988,6 +1000,43 @@
<data name="Run_PluginUseDescription.Text" xml:space="preserve">
<value>You can include or remove each plugin from the global results, change the direct activation phrase and configure additional options.</value>
</data>
<data name="Run_PositionAppearance_GroupSettings.Text" xml:space="preserve">
<value>Position &amp; appearance</value>
</data>
<data name="Run_PositionHeader.Text" xml:space="preserve">
<value>Show PowerToys Run on</value>
<comment>as in Show PowerToys Run on primary monitor</comment>
</data>
<data name="Run_Radio_Position_Cursor.Content" xml:space="preserve">
<value>Monitor with mouse cursor</value>
</data>
<data name="Run_Radio_Position_Focus.Content" xml:space="preserve">
<value>Monitor with focused window</value>
</data>
<data name="Run_Radio_Position_Primary_Monitor.Content" xml:space="preserve">
<value>Primary monitor</value>
</data>
<data name="Run_PluginsLoading.Text" xml:space="preserve">
<value>Plugins are loading...</value>
</data>
<data name="ColorPicker_ButtonDown.AutomationProperties.Name" xml:space="preserve">
<value>Move the color down</value>
</data>
<data name="ColorPicker_ButtonUp.AutomationProperties.Name" xml:space="preserve">
<value>Move the color up</value>
</data>
<data name="FancyZones_FlashZonesOnQuickSwitch.Content" xml:space="preserve">
<value>Flash zones when switching layout</value>
</data>
<data name="FancyZones_QuickLayoutSwitch.Content" xml:space="preserve">
<value>Enable quick layout switch</value>
</data>
<data name="FancyZones_QuickLayoutSwitch_GroupSettings.Text" xml:space="preserve">
<value>Quick layout switch</value>
</data>
<data name="ShortcutGuide_OpenShortcutGuide.Header" xml:space="preserve">
<value>Open Shortcut Guide</value>
</data>
<data name="Oobe_GetStarted.Text" xml:space="preserve">
<value>Let's get started!</value>
</data>
@ -1096,7 +1145,7 @@ From there, simply click on a Markdown file or SVG icon in the File Explorer and
<value>PowerToys Run supports various action keys to funnel search queries for a specific subset of results. Typing {&lt;} searches for running processes only, {?} will search only for file, or {.} for installed applications! See PowerToys documentation for the complete set of 'Action Keys' available.</value>
</data>
<data name="Oobe_ShortcutGuide_HowToLaunch.Text" xml:space="preserve">
<value>{Shift} + {Win} + {/} to open Shortcut Guide, press it again to close or press {Esc}.</value>
<value>{Win} + {?} to open Shortcut Guide, press it again to close or press {Esc}. You can also launch it by holding the {Win} key for one second!</value>
</data>
<data name="Oobe_TipsAndTricks.Text" xml:space="preserve">
<value>Tips &amp; tricks</value>
@ -1160,42 +1209,67 @@ From there, simply click on a Markdown file or SVG icon in the File Explorer and
<data name="SettingsWindow_Title" xml:space="preserve">
<value>PowerToys Settings</value>
</data>
<data name="Run_PositionAppearance_GroupSettings.Text" xml:space="preserve">
<value>Position &amp; appearance</value>
<data name="About_Espresso.Text" xml:space="preserve">
<value>About Espresso</value>
</data>
<data name="Run_PositionHeader.Text" xml:space="preserve">
<value>Show PowerToys Run on</value>
<comment>as in Show PowerToys Run on primary monitor</comment>
<data name="Espresso_Description.Text" xml:space="preserve">
<value>A convenient way to keep your PC awake on-demand.</value>
</data>
<data name="Run_Radio_Position_Cursor.Content" xml:space="preserve">
<value>Monitor with mouse cursor</value>
<data name="Espresso_EnableEspresso.Header" xml:space="preserve">
<value>Enable Espresso</value>
</data>
<data name="Run_Radio_Position_Focus.Content" xml:space="preserve">
<value>Monitor with focused window</value>
<data name="Espresso_NoKeepAwakeContent.Text" xml:space="preserve">
<value>Off (Passive)</value>
</data>
<data name="Run_Radio_Position_Primary_Monitor.Content" xml:space="preserve">
<value>Primary monitor</value>
<data name="Espresso_IndefiniteKeepAwakeContent.Text" xml:space="preserve">
<value>Keep awake indefinitely</value>
</data>
<data name="Run_PluginsLoading.Text" xml:space="preserve">
<value>Plugins are loading...</value>
<data name="Espresso_TemporaryKeepAwakeContent.Text" xml:space="preserve">
<value>Keep awake temporarily</value>
</data>
<data name="ColorPicker_ButtonDown.AutomationProperties.Name" xml:space="preserve">
<value>Move the color down</value>
<data name="Espresso_NoKeepAwakeDescription.Text" xml:space="preserve">
<value>Your PC operates according to its current power plan</value>
</data>
<data name="ColorPicker_ButtonUp.AutomationProperties.Name" xml:space="preserve">
<value>Move the color up</value>
<data name="Espresso_IndefiniteKeepAwakeDescription.Text" xml:space="preserve">
<value>Keeps your PC awake until the setting is disabled</value>
</data>
<data name="FancyZones_FlashZonesOnQuickSwitch.Content" xml:space="preserve">
<value>Flash zones when switching layout</value>
<data name="Espresso_TemporaryKeepAwakeDescription.Text" xml:space="preserve">
<value>Keeps your PC awake until the set time elapses</value>
</data>
<data name="FancyZones_QuickLayoutSwitch.Content" xml:space="preserve">
<value>Enable quick layout switch</value>
<data name="Espresso_EnableDisplayKeepAwake.Content" xml:space="preserve">
<value>Keep screen on</value>
</data>
<data name="FancyZones_QuickLayoutSwitch_GroupSettings.Text" xml:space="preserve">
<value>Quick layout switch</value>
<data name="Espresso_Mode.Text" xml:space="preserve">
<value>Mode</value>
</data>
<data name="ShortcutGuide_OpenShortcutGuide.Header" xml:space="preserve">
<value>Open Shortcut Guide</value>
<data name="Espresso_Behavior_GroupSettings.Text" xml:space="preserve">
<value>Behavior</value>
</data>
<data name="Espresso_TemporaryKeepAwake_Hours.Header" xml:space="preserve">
<value>Hours</value>
</data>
<data name="Espresso_TemporaryKeepAwake_Minutes.Header" xml:space="preserve">
<value>Minutes</value>
</data>
<data name="Espresso_ModuleAttributionLabel.Text" xml:space="preserve">
<value>Den Delimarsky's Espresso</value>
</data>
<data name="Espresso_ModuleAttributionHyperlink.NavigateUri" xml:space="preserve">
<value>https://espresso.den.dev</value>
<comment>URL. Do not loc</comment>
</data>
<data name="Oobe_Espresso" xml:space="preserve">
<value>Espresso</value>
<comment>Module name, do not loc</comment>
</data>
<data name="Oobe_Espresso_Description" xml:space="preserve">
<value>Espresso is a Windows tool designed to keep your PC awake on-demand without having to manage its power settings. This behavior can be helpful when running time-consuming tasks while ensuring that your PC does not go to sleep or turn off its screens.</value>
</data>
<data name="Oobe_Espresso_HowToUse.Text" xml:space="preserve">
<value>Open {PowerToys Settings} and enable Espresso</value>
</data>
<data name="Oobe_Espresso_TipsAndTricks.Text" xml:space="preserve">
<value>You can always change modes quickly by {right-clicking the Espresso icon} in the system tray.</value>
</data>
<data name="General_FailedToDownloadTheNewVersion.Text" xml:space="preserve">
<value>An error occurred trying to update to</value>

View File

@ -0,0 +1,188 @@
<Page
x:Class="Microsoft.PowerToys.Settings.UI.Views.EspressoPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:c="using:Microsoft.PowerToys.Settings.UI.Converters"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
AutomationProperties.LandmarkType="Main">
<Page.Resources>
<c:EspressoModeToBoolConverter x:Key="EspressoModeToBoolConverter" />
</Page.Resources>
<Grid RowSpacing="{StaticResource DefaultRowSpacing}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="LayoutVisualStates">
<VisualState x:Name="WideLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource WideLayoutMinWidth}" />
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="SmallLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource SmallLayoutMinWidth}" />
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="SidePanel.(Grid.Column)" Value="0" />
<Setter Target="SidePanel.Width" Value="Auto" />
<Setter Target="LinksPanel.(RelativePanel.RightOf)" Value="AboutImage" />
<Setter Target="LinksPanel.(RelativePanel.AlignTopWith)" Value="AboutImage" />
<Setter Target="AboutImage.Margin" Value="0,12,12,0" />
<Setter Target="AboutTitle.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical"
x:Name="EspressoView"
HorizontalAlignment="Left"
Margin="0,0,48,0"
MaxWidth="{StaticResource MaxContentWidth}">
<ToggleSwitch x:Uid="Espresso_EnableEspresso" IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
<TextBlock x:Uid="Espresso_Behavior_GroupSettings"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
Style="{StaticResource SettingsGroupTitleStyle}"/>
<CheckBox x:Uid="Espresso_EnableDisplayKeepAwake"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
IsChecked="{x:Bind ViewModel.KeepDisplayOn, Mode=TwoWay}"
Margin="{StaticResource XSmallTopMargin}" />
<TextBlock x:Uid="Espresso_Mode"
Margin="{StaticResource SmallTopMargin}"
x:Name="ModeTitleLabel"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}" />
<StackPanel AutomationProperties.LabeledBy="{Binding ElementName=ModeTitleLabel}"
Margin="0,-8,0,0">
<RadioButton x:Uid="Espresso_NoKeepAwake"
Margin="{StaticResource SmallTopMargin}"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
IsChecked="{x:Bind Path=ViewModel.Mode, Mode=TwoWay, Converter={StaticResource EspressoModeToBoolConverter}, ConverterParameter=0}">
<RadioButton.Content>
<TextBlock TextWrapping="WrapWholeWords" LineHeight="20">
<Run x:Uid="Espresso_NoKeepAwakeContent"/>
<LineBreak/>
<Run Foreground="{ThemeResource SystemBaseMediumColor}"
x:Uid="Espresso_NoKeepAwakeDescription"/>
</TextBlock>
</RadioButton.Content>
</RadioButton>
<RadioButton x:Uid="Espresso_IndefiniteKeepAwake"
Margin="{StaticResource SmallTopMargin}"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
IsChecked="{x:Bind Path=ViewModel.Mode, Mode=TwoWay, Converter={StaticResource EspressoModeToBoolConverter}, ConverterParameter=1}">
<RadioButton.Content>
<TextBlock TextWrapping="WrapWholeWords" LineHeight="20">
<Run x:Uid="Espresso_IndefiniteKeepAwakeContent"/>
<LineBreak/>
<Run Foreground="{ThemeResource SystemBaseMediumColor}"
x:Uid="Espresso_IndefiniteKeepAwakeDescription"/>
</TextBlock>
</RadioButton.Content>
</RadioButton>
<RadioButton x:Uid="Espresso_TemporaryKeepAwake"
Margin="{StaticResource SmallTopMargin}"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
IsChecked="{x:Bind Path=ViewModel.Mode, Mode=TwoWay, Converter={StaticResource EspressoModeToBoolConverter}, ConverterParameter=2}">
<RadioButton.Content>
<TextBlock TextWrapping="WrapWholeWords" LineHeight="20">
<Run x:Uid="Espresso_TemporaryKeepAwakeContent"/>
<LineBreak/>
<Run Foreground="{ThemeResource SystemBaseMediumColor}"
x:Uid="Espresso_TemporaryKeepAwakeDescription"/>
</TextBlock>
</RadioButton.Content>
</RadioButton>
<StackPanel Margin="28,8,0,0" Orientation="Horizontal">
<muxc:NumberBox x:Uid="Espresso_TemporaryKeepAwake_Hours"
Value="{x:Bind ViewModel.Hours, Mode=TwoWay}"
Minimum="0"
SpinButtonPlacementMode="Compact"
HorizontalAlignment="Left"
MinWidth="90"
IsEnabled="{x:Bind ViewModel.IsTimeConfigurationEnabled, Mode=OneWay}"
SmallChange="1"
LargeChange="5"/>
<muxc:NumberBox x:Uid="Espresso_TemporaryKeepAwake_Minutes"
Value="{x:Bind ViewModel.Minutes, Mode=TwoWay}"
Minimum="0"
SpinButtonPlacementMode="Compact"
Margin="8,0,0,0"
HorizontalAlignment="Left"
IsEnabled="{x:Bind ViewModel.IsTimeConfigurationEnabled, Mode=OneWay}"
MinWidth="90"
SmallChange="1"
LargeChange="5"/>
</StackPanel>
</StackPanel>
</StackPanel>
<RelativePanel x:Name="SidePanel"
HorizontalAlignment="Left"
Width="{StaticResource SidePanelWidth}"
Grid.Column="1">
<StackPanel x:Name="DescriptionPanel">
<TextBlock x:Uid="About_Espresso"
x:Name="AboutTitle"
Grid.ColumnSpan="2"
Style="{StaticResource SettingsGroupTitleStyle}"
Margin="{StaticResource XSmallBottomMargin}"/>
<TextBlock x:Uid="Espresso_Description"
TextWrapping="Wrap"
Grid.Row="1" />
</StackPanel>
<Border x:Name="AboutImage"
CornerRadius="4"
Grid.Row="2"
MaxWidth="240"
HorizontalAlignment="Left"
Margin="{StaticResource SmallTopBottomMargin}"
RelativePanel.Below="DescriptionPanel">
<HyperlinkButton x:Uid="Espresso_ImageHyperlinkToDocs">
<Image x:Uid="Espresso_Image" Source="ms-appx:///Assets/Modules/Espresso.png" />
</HyperlinkButton>
</Border>
<StackPanel x:Name="LinksPanel"
Margin="0,1,0,0"
RelativePanel.Below="AboutImage"
Orientation="Vertical" >
<HyperlinkButton x:Uid="Espresso_ImageHyperlinkToDocs">
<TextBlock x:Uid="Module_overview" />
</HyperlinkButton>
<HyperlinkButton NavigateUri="https://aka.ms/powerToysGiveFeedback">
<TextBlock x:Uid="Give_Feedback" />
</HyperlinkButton>
<TextBlock
x:Uid="AttributionTitle"
Style="{StaticResource SettingsGroupTitleStyle}" />
<HyperlinkButton Margin="0,-3,0,0"
x:Uid="Espresso_ModuleAttributionHyperlink">
<TextBlock x:Uid="Espresso_ModuleAttributionLabel"
TextWrapping="Wrap" />
</HyperlinkButton>
</StackPanel>
</RelativePanel>
</Grid>
</Page>

View File

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.ViewModels;
using Windows.UI.Xaml.Controls;
namespace Microsoft.PowerToys.Settings.UI.Views
{
public sealed partial class EspressoPage : Page
{
private EspressoViewModel ViewModel { get; set; }
public EspressoPage()
{
var settingsUtils = new SettingsUtils();
ViewModel = new EspressoViewModel(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<EspressoSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
DataContext = ViewModel;
InitializeComponent();
}
}
}

View File

@ -41,7 +41,13 @@
<FontIcon Glyph="&#xEF3C;"/>
</winui:NavigationViewItem.Icon>
</winui:NavigationViewItem>
<winui:NavigationViewItem x:Uid="Shell_Espresso" helpers:NavHelper.NavigateTo="views:EspressoPage" AutomationProperties.HeadingLevel="Level1">
<winui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xEC32;"/>
</winui:NavigationViewItem.Icon>
</winui:NavigationViewItem>
<winui:NavigationViewItem x:Uid="Shell_FancyZones" helpers:NavHelper.NavigateTo="views:FancyZonesPage" AutomationProperties.HeadingLevel="Level1">
<winui:NavigationViewItem.Icon>
<PathIcon Data="M45,48H25.5V45H45V25.5H25.5v-3H45V3H25.5V0H48V48ZM22.5,48H3V45H22.5V3H3V0H25.5V48ZM0,48V0H3V48Z"/>

View File

@ -34,6 +34,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutputPath>..\..\..\$(Platform)\$(Configuration)\Settings</OutputPath>
<Optimize>false</Optimize>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">