[Shortcut Guide] Move into separate process (#11359)
1
.github/actions/spell-check/expect.txt
vendored
@ -112,6 +112,7 @@ atlstr
|
|||||||
attr
|
attr
|
||||||
Attribs
|
Attribs
|
||||||
aumid
|
aumid
|
||||||
|
Aut
|
||||||
AUTHN
|
AUTHN
|
||||||
AUTOAPPEND
|
AUTOAPPEND
|
||||||
autocomplete
|
autocomplete
|
||||||
|
@ -147,7 +147,8 @@ build:
|
|||||||
- 'modules\launcher\Wox.Plugin.dll'
|
- 'modules\launcher\Wox.Plugin.dll'
|
||||||
- 'modules\Microsoft.Launcher.dll'
|
- 'modules\Microsoft.Launcher.dll'
|
||||||
- 'modules\PowerRename\PowerRenameExt.dll'
|
- 'modules\PowerRename\PowerRenameExt.dll'
|
||||||
- 'modules\ShortcutGuide\ShortcutGuide.dll'
|
- 'modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe'
|
||||||
|
- 'modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.dll'
|
||||||
- 'Notifications.dll'
|
- 'Notifications.dll'
|
||||||
- 'os-detection.dll'
|
- 'os-detection.dll'
|
||||||
- 'PowerToys.exe'
|
- 'PowerToys.exe'
|
||||||
|
@ -22,15 +22,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner
|
|||||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B} = {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}
|
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B} = {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}
|
||||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {B25AC7A5-FB9F-4789-B392-D5C85E948670}
|
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {B25AC7A5-FB9F-4789-B392-D5C85E948670}
|
||||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1} = {AF2349B8-E5B6-4004-9502-687C1C7730B1}
|
{AF2349B8-E5B6-4004-9502-687C1C7730B1} = {AF2349B8-E5B6-4004-9502-687C1C7730B1}
|
||||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA} = {A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}
|
|
||||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
||||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}
|
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}
|
||||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA} = {655C9AF2-18D3-4DA6-80E4-85504A7722BA}
|
{655C9AF2-18D3-4DA6-80E4-85504A7722BA} = {655C9AF2-18D3-4DA6-80E4-85504A7722BA}
|
||||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9} = {89F34AF7-1C34-4A72-AA6E-534BCF972BD9}
|
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9} = {89F34AF7-1C34-4A72-AA6E-534BCF972BD9}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuide", "src\modules\shortcut_guide\shortcut_guide.vcxproj", "{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{4574FDD0-F61D-4376-98BF-E5A1262C11EC}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{4574FDD0-F61D-4376-98BF-E5A1262C11EC}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "interface", "interface", "{3BB8493E-D18E-4485-A320-CB40F90F55AE}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "interface", "interface", "{3BB8493E-D18E-4485-A320-CB40F90F55AE}"
|
||||||
@ -324,6 +321,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorLibrar
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorTest", "src\modules\keyboardmanager\KeyboardManagerEditorTest\KeyboardManagerEditorTest.vcxproj", "{62173D9A-6724-4C00-A1C8-FB646480A9EC}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorTest", "src\modules\keyboardmanager\KeyboardManagerEditorTest\KeyboardManagerEditorTest.vcxproj", "{62173D9A-6724-4C00-A1C8-FB646480A9EC}"
|
||||||
EndProject
|
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}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuide", "src\modules\ShortcutGuide\ShortcutGuide\ShortcutGuide.vcxproj", "{2EDB3EB4-FA92-4BFF-B2D8-566584837231}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
@ -334,10 +337,6 @@ Global
|
|||||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.Build.0 = Debug|x64
|
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.Build.0 = Debug|x64
|
||||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.ActiveCfg = Release|x64
|
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.ActiveCfg = Release|x64
|
||||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.Build.0 = Release|x64
|
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.Build.0 = Release|x64
|
||||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Release|x64.Build.0 = Release|x64
|
|
||||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.ActiveCfg = Debug|x64
|
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.Build.0 = Debug|x64
|
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.Build.0 = Debug|x64
|
||||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.ActiveCfg = Release|x64
|
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.ActiveCfg = Release|x64
|
||||||
@ -660,12 +659,19 @@ Global
|
|||||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.Build.0 = Debug|x64
|
{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.ActiveCfg = Release|x64
|
||||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.Build.0 = Release|x64
|
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.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
|
||||||
|
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.Build.0 = Release|x64
|
||||||
|
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
|
||||||
{3BB8493E-D18E-4485-A320-CB40F90F55AE} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
{3BB8493E-D18E-4485-A320-CB40F90F55AE} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||||
{D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
{D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||||
@ -759,6 +765,9 @@ Global
|
|||||||
{8DF78B53-200E-451F-9328-01EB907193AE} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
{8DF78B53-200E-451F-9328-01EB907193AE} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49} = {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}
|
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||||
|
{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}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||||
|
@ -6,13 +6,14 @@
|
|||||||
<?define ImageResizerProjectName="ImageResizer"?>
|
<?define ImageResizerProjectName="ImageResizer"?>
|
||||||
<?define KeyboardManagerProjectName="KeyboardManager"?>
|
<?define KeyboardManagerProjectName="KeyboardManager"?>
|
||||||
<?define PowerRenameProjectName="PowerRename"?>
|
<?define PowerRenameProjectName="PowerRename"?>
|
||||||
<?define ShortcutGuideProjectName="ShortcutGuide"?>
|
|
||||||
<?define ColorPickerProjectName="ColorPicker"?>
|
<?define ColorPickerProjectName="ColorPicker"?>
|
||||||
|
|
||||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||||
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
|
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
|
||||||
|
<?define ShortcutGuideExecutable=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuide?>
|
||||||
<Product Id="*"
|
<?define ShortcutGuideModuleInterface=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuideModuleInterface?>
|
||||||
|
|
||||||
|
<Product Id="*"
|
||||||
Name="PowerToys (Preview)"
|
Name="PowerToys (Preview)"
|
||||||
Language="1033"
|
Language="1033"
|
||||||
Version="$(var.Version)"
|
Version="$(var.Version)"
|
||||||
@ -205,11 +206,16 @@
|
|||||||
<Directory Id="ProgramFiles64Folder">
|
<Directory Id="ProgramFiles64Folder">
|
||||||
<Directory Id="INSTALLFOLDER" Name="PowerToys">
|
<Directory Id="INSTALLFOLDER" Name="PowerToys">
|
||||||
<Directory Id="SvgsInstallFolder" Name="svgs"/>
|
<Directory Id="SvgsInstallFolder" Name="svgs"/>
|
||||||
<Directory Id="ToolsFolder" Name="Tools"/>
|
<Directory Id="ToolsFolder" Name="Tools"/>
|
||||||
<Directory Id="ModulesInstallFolder" Name="modules">
|
<Directory Id="ModulesInstallFolder" Name="modules">
|
||||||
<Directory Id="ImageResizerInstallFolder" Name="$(var.ImageResizerProjectName)" />
|
<Directory Id="ImageResizerInstallFolder" Name="$(var.ImageResizerProjectName)" />
|
||||||
<Directory Id="PowerRenameInstallFolder" Name="$(var.PowerRenameProjectName)"/>
|
<Directory Id="PowerRenameInstallFolder" Name="$(var.PowerRenameProjectName)"/>
|
||||||
<Directory Id="ShortcutGuideInstallFolder" Name="$(var.ShortcutGuideProjectName)"/>
|
<Directory Id="ShortcutGuideInstallFolder" Name="ShortcutGuide">
|
||||||
|
<Directory Id="ShortcutGuideExecutableInstallFolder" Name="ShortcutGuide">
|
||||||
|
<Directory Id="ShortcutGuideSvgsInstallFolder" Name="svgs"/>
|
||||||
|
</Directory>
|
||||||
|
<Directory Id="ShortcutGuideModuleInterfaceInstallFolder" Name="ShortcutGuideModuleInterface"/>
|
||||||
|
</Directory>
|
||||||
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
||||||
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
||||||
<Directory Id="KeyboardManagerInstallFolder" Name="$(var.KeyboardManagerProjectName)">
|
<Directory Id="KeyboardManagerInstallFolder" Name="$(var.KeyboardManagerProjectName)">
|
||||||
@ -355,21 +361,21 @@
|
|||||||
</Component>
|
</Component>
|
||||||
</DirectoryRef>
|
</DirectoryRef>
|
||||||
|
|
||||||
<DirectoryRef Id="SvgsInstallFolder" FileSource="$(var.BinX64Dir)svgs\">
|
<DirectoryRef Id="ShortcutGuideSvgsInstallFolder" FileSource="$(var.ShortcutGuideExecutable)\svgs\">
|
||||||
<Component Id="PowerToysSvgs" Guid="7C4D4EED-9338-423D-992C-DCE02F3E2D35" Win64="yes">
|
<Component Id="ShortcutGuideSvgs" Guid="7C4D4EED-9338-423D-992C-DCE02F3E2D35" Win64="yes">
|
||||||
<File Source="$(var.BinX64Dir)svgs\0.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\0.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\1.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\1.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\2.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\2.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\3.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\3.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\4.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\4.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\5.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\5.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\6.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\6.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\7.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\7.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\8.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\8.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\9.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\9.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\no_active_window.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\no_active_window.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\overlay.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\overlay.svg" />
|
||||||
<File Source="$(var.BinX64Dir)svgs\overlay_portrait.svg" />
|
<File Source="$(var.ShortcutGuideExecutable)\svgs\overlay_portrait.svg" />
|
||||||
</Component>
|
</Component>
|
||||||
</DirectoryRef>
|
</DirectoryRef>
|
||||||
<DirectoryRef Id="FancyZonesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
|
<DirectoryRef Id="FancyZonesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
|
||||||
@ -582,9 +588,15 @@
|
|||||||
</Component>
|
</Component>
|
||||||
</DirectoryRef>
|
</DirectoryRef>
|
||||||
|
|
||||||
<DirectoryRef Id="ShortcutGuideInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.ShortcutGuideProjectName)\">
|
<DirectoryRef Id="ShortcutGuideModuleInterfaceInstallFolder" FileSource="$(var.ShortcutGuideModuleInterface)">
|
||||||
<Component Id="Module_ShortcutGuide" Guid="CBD0AC09-91D3-428E-B2B3-05745ADF3473" Win64="yes">
|
<Component Id="Module_ShortcutGuideModuleInterface" Guid="CBD0AC09-91D3-428E-B2B3-05745ADF3473" Win64="yes">
|
||||||
<File Source="$(var.BinX64Dir)modules\$(var.ShortcutGuideProjectName)\$(var.ShortcutGuideProjectName).dll" KeyPath="yes" />
|
<File Source="$(var.ShortcutGuideModuleInterface)\ShortcutGuideModuleInterface.dll" KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
</DirectoryRef>
|
||||||
|
|
||||||
|
<DirectoryRef Id="ShortcutGuideExecutableInstallFolder" FileSource="$(var.ShortcutGuideExecutable)">
|
||||||
|
<Component Id="Module_ShortcutGuideExecutable" Guid="DA6E5710-F1DF-44EB-A316-300FA39544E9" Win64="yes">
|
||||||
|
<File Source="$(var.ShortcutGuideExecutable)\PowerToys.ShortcutGuide.exe" KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
</DirectoryRef>
|
</DirectoryRef>
|
||||||
|
|
||||||
@ -786,8 +798,9 @@
|
|||||||
<ComponentRef Id="Notice_md" />
|
<ComponentRef Id="Notice_md" />
|
||||||
<ComponentRef Id="powertoysinterop_dll" />
|
<ComponentRef Id="powertoysinterop_dll" />
|
||||||
<ComponentRef Id="vcredist_dlls" />
|
<ComponentRef Id="vcredist_dlls" />
|
||||||
<ComponentRef Id="PowerToysSvgs" />
|
<ComponentRef Id="ShortcutGuideSvgs" />
|
||||||
<ComponentRef Id="Module_ShortcutGuide" />
|
<ComponentRef Id="Module_ShortcutGuideModuleInterface" />
|
||||||
|
<ComponentRef Id="Module_ShortcutGuideExecutable" />
|
||||||
<ComponentRef Id="Module_FancyZones" />
|
<ComponentRef Id="Module_FancyZones" />
|
||||||
<ComponentRef Id="DesktopShortcut" />
|
<ComponentRef Id="DesktopShortcut" />
|
||||||
<ComponentRef Id="Module_PowerRename" />
|
<ComponentRef Id="Module_PowerRename" />
|
||||||
|
@ -155,7 +155,33 @@ namespace PowerToysSettings
|
|||||||
return get_modifiers_repeat() | MOD_NOREPEAT;
|
return get_modifiers_repeat() | MOD_NOREPEAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
std::wstring to_string()
|
||||||
|
{
|
||||||
|
std::wstring result = L"";
|
||||||
|
if (shift_pressed())
|
||||||
|
{
|
||||||
|
result += L"shift+";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctrl_pressed())
|
||||||
|
{
|
||||||
|
result += L"ctrl+";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win_pressed())
|
||||||
|
{
|
||||||
|
result += L"win+";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alt_pressed())
|
||||||
|
{
|
||||||
|
result += L"alt+";
|
||||||
|
}
|
||||||
|
|
||||||
|
result += key_from_code(get_code());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static std::wstring key_from_code(UINT key_code)
|
static std::wstring key_from_code(UINT key_code)
|
||||||
{
|
{
|
||||||
auto layout = GetKeyboardLayout(0);
|
auto layout = GetKeyboardLayout(0);
|
||||||
@ -209,6 +235,8 @@ namespace PowerToysSettings
|
|||||||
}
|
}
|
||||||
return L"(Key " + std::to_wstring(key_code) + L")";
|
return L"(Key " + std::to_wstring(key_code) + L")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
HotkeyObject(json::JsonObject hotkey_json) :
|
HotkeyObject(json::JsonObject hotkey_json) :
|
||||||
m_json(std::move(hotkey_json))
|
m_json(std::move(hotkey_json))
|
||||||
{
|
{
|
||||||
|
@ -150,10 +150,6 @@ public
|
|||||||
|
|
||||||
static String ^ ShowColorPickerSharedEvent() {
|
static String ^ ShowColorPickerSharedEvent() {
|
||||||
return gcnew String(CommonSharedConstants::SHOW_COLOR_PICKER_SHARED_EVENT);
|
return gcnew String(CommonSharedConstants::SHOW_COLOR_PICKER_SHARED_EVENT);
|
||||||
}
|
|
||||||
|
|
||||||
static String ^ ShowShortcutGuideSharedEvent() {
|
|
||||||
return gcnew String(CommonSharedConstants::SHOW_SHORTCUT_GUIDE_SHARED_EVENT);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,7 @@ namespace CommonSharedConstants
|
|||||||
// Path to the event used to show Color Picker
|
// Path to the event used to show Color Picker
|
||||||
const wchar_t SHOW_COLOR_PICKER_SHARED_EVENT[] = L"Local\\ShowColorPickerEvent-8c46be2a-3e05-4186-b56b-4ae986ef2525";
|
const wchar_t SHOW_COLOR_PICKER_SHARED_EVENT[] = L"Local\\ShowColorPickerEvent-8c46be2a-3e05-4186-b56b-4ae986ef2525";
|
||||||
|
|
||||||
// Path to the event used to show Shortcut Guide
|
const wchar_t SHORTCUT_GUIDE_EXIT_EVENT[] = L"Local\\ShortcutGuide-ExitEvent-35697cdd-a3d2-47d6-a246-34efcc73eac0";
|
||||||
const wchar_t SHOW_SHORTCUT_GUIDE_SHARED_EVENT[] = L"Local\\ShowShortcutGuideEvent-6982d682-7462-404f-95af-86ae3f089c4f";
|
|
||||||
|
|
||||||
// Max DWORD for key code to disable keys.
|
// Max DWORD for key code to disable keys.
|
||||||
const int VK_DISABLED = 0x100;
|
const int VK_DISABLED = 0x100;
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
"LanguageSet": "Azure_Languages",
|
"LanguageSet": "Azure_Languages",
|
||||||
"LocItems": [
|
"LocItems": [
|
||||||
{
|
{
|
||||||
"SourceFile": "src\\modules\\shortcut_guide\\Resources.resx",
|
"SourceFile": "src\\modules\\ShortcutGuide\\ShortcutGuide\\Resources.resx",
|
||||||
"CopyOption": "LangIDOnName",
|
"CopyOption": "LangIDOnName",
|
||||||
"OutputPath": "src\\modules\\shortcut_guide"
|
"OutputPath": "src\\modules\\ShortcutGuide\\ShortcutGuide"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
16
src/modules/ShortcutGuide/ShortcutGuide/PropertySheet.props
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ImportGroup Label="PropertySheets" />
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<!--
|
||||||
|
To customize common C++/WinRT project properties:
|
||||||
|
* right-click the project node
|
||||||
|
* expand the Common Properties item
|
||||||
|
* select the C++/WinRT property page
|
||||||
|
|
||||||
|
For more advanced scenarios, and complete documentation, please see:
|
||||||
|
https://github.com/Microsoft/cppwinrt/tree/master/nuget
|
||||||
|
-->
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemDefinitionGroup />
|
||||||
|
</Project>
|
@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="Setting_Description_Press_Time" xml:space="preserve">
|
|
||||||
<value>How long to press the Windows key before showing the Shortcut Guide (ms)</value>
|
|
||||||
</data>
|
|
||||||
<data name="Setting_Description_Overlay_Opacity" xml:space="preserve">
|
<data name="Setting_Description_Overlay_Opacity" xml:space="preserve">
|
||||||
<value>Opacity of the Shortcut Guide's overlay background (%)</value>
|
<value>Opacity of the Shortcut Guide's overlay background (%)</value>
|
||||||
</data>
|
</data>
|
BIN
src/modules/ShortcutGuide/ShortcutGuide/Shortcut-Guide.ico
Normal file
After Width: | Height: | Size: 17 KiB |
@ -0,0 +1,54 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include "Generated Files/resource.h"
|
||||||
|
#include "../../../../common/version/version.h"
|
||||||
|
|
||||||
|
#define APSTUDIO_READONLY_SYMBOLS
|
||||||
|
#include "winres.h"
|
||||||
|
#undef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Icon
|
||||||
|
//
|
||||||
|
|
||||||
|
// Icon with lowest ID value placed first to ensure application icon
|
||||||
|
// remains consistent on all systems.
|
||||||
|
IDI_ICON1 ICON "Shortcut-Guide.ico"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Version
|
||||||
|
//
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION FILE_VERSION
|
||||||
|
PRODUCTVERSION PRODUCT_VERSION
|
||||||
|
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS VS_FF_DEBUG
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS VOS_NT_WINDOWS32
|
||||||
|
FILETYPE VFT_DLL
|
||||||
|
FILESUBTYPE VFT2_UNKNOWN
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", COMPANY_NAME
|
||||||
|
VALUE "FileDescription", FILE_DESCRIPTION
|
||||||
|
VALUE "FileVersion", FILE_VERSION_STRING
|
||||||
|
VALUE "InternalName", INTERNAL_NAME
|
||||||
|
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||||
|
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||||
|
VALUE "ProductName", PRODUCT_NAME
|
||||||
|
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
</assembly>
|
189
src/modules/ShortcutGuide/ShortcutGuide/ShortcutGuide.vcxproj
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
<?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')" />
|
||||||
|
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
|
||||||
|
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h ShortcutGuide.base.rc ShortcutGuide.rc" />
|
||||||
|
</Target>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<CppWinRTOptimized>true</CppWinRTOptimized>
|
||||||
|
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
|
||||||
|
<CppWinRTGenerateWindowsMetadata>true</CppWinRTGenerateWindowsMetadata>
|
||||||
|
<MinimalCoreWin>true</MinimalCoreWin>
|
||||||
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{2edb3eb4-fa92-4bff-b2d8-566584837231}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>ShortcutGuide</RootNamespace>
|
||||||
|
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="PropertySheet.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetName>PowerToys.$(MSBuildProjectName)</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\ShortcutGuide\$(ProjectName)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\ShortcutGuide\$(ProjectName)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\..\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>ole32.lib;Shell32.lib;OleAut32.lib;Dbghelp.lib;Dwmapi.lib;Dcomp.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="animation.h" />
|
||||||
|
<ClInclude Include="d2d_svg.h" />
|
||||||
|
<ClInclude Include="d2d_text.h" />
|
||||||
|
<ClInclude Include="d2d_window.h" />
|
||||||
|
<ClInclude Include="Generated Files\resource.h" />
|
||||||
|
<ClInclude Include="native_event_waiter.h" />
|
||||||
|
<ClInclude Include="overlay_window.h" />
|
||||||
|
<ClInclude Include="pch.h" />
|
||||||
|
<ClInclude Include="resource.base.h" />
|
||||||
|
<ClInclude Include="ShortcutGuideSettings.h" />
|
||||||
|
<ClInclude Include="ShortcutGuideConstants.h" />
|
||||||
|
<ClInclude Include="shortcut_guide.h" />
|
||||||
|
<ClInclude Include="start_visible.h" />
|
||||||
|
<ClInclude Include="target_state.h" />
|
||||||
|
<ClInclude Include="tasklist_positions.h" />
|
||||||
|
<ClInclude Include="trace.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="animation.cpp" />
|
||||||
|
<ClCompile Include="d2d_svg.cpp" />
|
||||||
|
<ClCompile Include="d2d_text.cpp" />
|
||||||
|
<ClCompile Include="d2d_window.cpp" />
|
||||||
|
<ClCompile Include="main.cpp" />
|
||||||
|
<ClCompile Include="native_event_waiter.cpp" />
|
||||||
|
<ClCompile Include="overlay_window.cpp" />
|
||||||
|
<ClCompile Include="pch.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="shortcut_guide.cpp" />
|
||||||
|
<ClCompile Include="start_visible.cpp" />
|
||||||
|
<ClCompile Include="target_state.cpp" />
|
||||||
|
<ClCompile Include="tasklist_positions.cpp" />
|
||||||
|
<ClCompile Include="trace.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
<None Include="PropertySheet.props" />
|
||||||
|
<CopyFileToFolders Include="svgs\0.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\1.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\2.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\3.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\4.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\5.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\6.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\7.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\8.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\9.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\no_active_window.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\overlay.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\overlay_portrait.svg">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
<DestinationFolders>$(OutDir)\svgs</DestinationFolders>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\common\Display\Display.vcxproj">
|
||||||
|
<Project>{caba8dfb-823b-4bf2-93ac-3f31984150d9}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||||
|
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\common\Themes\Themes.vcxproj">
|
||||||
|
<Project>{98537082-0fdb-40de-abd8-0dc5a4269bab}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Resources.resx" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="Generated Files\ShortcutGuide.rc" />
|
||||||
|
<None Include="ShortcutGuide.base.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Image Include="Shortcut-Guide.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Manifest Include="ShortcutGuide.exe.manifest" />
|
||||||
|
</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>
|
@ -0,0 +1,180 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="svgs">
|
||||||
|
<UniqueIdentifier>{800507f8-718d-48d1-aa56-96c040795b8a}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Generated Files">
|
||||||
|
<UniqueIdentifier>{cb917ac7-30da-494b-81f1-cbe4415e91f4}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="pch.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="animation.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="d2d_svg.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="d2d_text.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="d2d_window.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="native_event_waiter.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="overlay_window.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="shortcut_guide.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ShortcutGuideConstants.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="start_visible.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="target_state.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="tasklist_positions.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="trace.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="resource.base.h">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Generated Files\resource.h">
|
||||||
|
<Filter>Generated Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ShortcutGuideSettings.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="pch.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="main.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="animation.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="d2d_svg.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="d2d_text.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="d2d_window.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="native_event_waiter.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="overlay_window.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="shortcut_guide.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="start_visible.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="target_state.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="tasklist_positions.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="trace.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="PropertySheet.props" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
<None Include="ShortcutGuide.base.rc">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<CopyFileToFolders Include="svgs\0.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\1.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\2.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\3.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\4.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\5.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\6.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\7.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\8.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\9.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\no_active_window.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\overlay.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
<CopyFileToFolders Include="svgs\overlay_portrait.svg">
|
||||||
|
<Filter>svgs</Filter>
|
||||||
|
</CopyFileToFolders>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Resources.resx">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="Generated Files\ShortcutGuide.rc">
|
||||||
|
<Filter>Generated Files</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Image Include="Shortcut-Guide.ico">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</Image>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Manifest Include="ShortcutGuide.exe.manifest" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct ShortcutGuideSettings
|
||||||
|
{
|
||||||
|
std::wstring hotkey = L"shift+win+/";
|
||||||
|
int overlayOpacity = 90;
|
||||||
|
std::wstring theme = L"system";
|
||||||
|
std::wstring disabledApps = L"";
|
||||||
|
};
|
@ -5,17 +5,20 @@ D2DSVG& D2DSVG::load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc)
|
|||||||
{
|
{
|
||||||
svg = nullptr;
|
svg = nullptr;
|
||||||
winrt::com_ptr<IStream> svg_stream;
|
winrt::com_ptr<IStream> svg_stream;
|
||||||
winrt::check_hresult(SHCreateStreamOnFileEx(filename.c_str(),
|
auto h = SHCreateStreamOnFileEx(filename.c_str(),
|
||||||
STGM_READ,
|
STGM_READ,
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
FALSE,
|
FALSE,
|
||||||
nullptr,
|
nullptr,
|
||||||
svg_stream.put()));
|
svg_stream.put());
|
||||||
|
winrt::check_hresult(h);
|
||||||
|
|
||||||
winrt::check_hresult(d2d_dc->CreateSvgDocument(
|
auto h1 = d2d_dc->CreateSvgDocument(
|
||||||
svg_stream.get(),
|
svg_stream.get(),
|
||||||
D2D1::SizeF(1, 1),
|
D2D1::SizeF(1, 1),
|
||||||
svg.put()));
|
svg.put());
|
||||||
|
|
||||||
|
winrt::check_hresult(h1);
|
||||||
|
|
||||||
winrt::com_ptr<ID2D1SvgElement> root;
|
winrt::com_ptr<ID2D1SvgElement> root;
|
||||||
svg->GetRoot(root.put());
|
svg->GetRoot(root.put());
|
@ -3,8 +3,7 @@
|
|||||||
|
|
||||||
#include <common/utils/resources.h>
|
#include <common/utils/resources.h>
|
||||||
|
|
||||||
D2DWindow::D2DWindow(std::optional<std::function<std::remove_pointer_t<WNDPROC>>> _pre_wnd_proc) :
|
D2DWindow::D2DWindow()
|
||||||
pre_wnd_proc(std::move(_pre_wnd_proc))
|
|
||||||
{
|
{
|
||||||
static const WCHAR* class_name = L"PToyD2DPopup";
|
static const WCHAR* class_name = L"PToyD2DPopup";
|
||||||
WNDCLASS wc = {};
|
WNDCLASS wc = {};
|
||||||
@ -190,10 +189,6 @@ D2DWindow* D2DWindow::this_from_hwnd(HWND window)
|
|||||||
LRESULT __stdcall D2DWindow::d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
|
LRESULT __stdcall D2DWindow::d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
|
||||||
{
|
{
|
||||||
auto self = this_from_hwnd(window);
|
auto self = this_from_hwnd(window);
|
||||||
if (self && self->pre_wnd_proc.has_value())
|
|
||||||
{
|
|
||||||
(*self->pre_wnd_proc)(window, message, wparam, lparam);
|
|
||||||
}
|
|
||||||
switch (message)
|
switch (message)
|
||||||
{
|
{
|
||||||
case WM_NCCREATE:
|
case WM_NCCREATE:
|
@ -17,7 +17,7 @@
|
|||||||
class D2DWindow
|
class D2DWindow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
D2DWindow(std::optional<std::function<std::remove_pointer_t<WNDPROC>>> pre_wnd_proc = std::nullopt);
|
D2DWindow();
|
||||||
void show(UINT x, UINT y, UINT width, UINT height);
|
void show(UINT x, UINT y, UINT width, UINT height);
|
||||||
void hide();
|
void hide();
|
||||||
void initialize();
|
void initialize();
|
||||||
@ -62,6 +62,4 @@ protected:
|
|||||||
winrt::com_ptr<ID2D1Factory6> d2d_factory;
|
winrt::com_ptr<ID2D1Factory6> d2d_factory;
|
||||||
winrt::com_ptr<ID2D1Device5> d2d_device;
|
winrt::com_ptr<ID2D1Device5> d2d_device;
|
||||||
winrt::com_ptr<ID2D1DeviceContext5> d2d_dc;
|
winrt::com_ptr<ID2D1DeviceContext5> d2d_dc;
|
||||||
|
|
||||||
std::optional<std::function<std::remove_pointer_t<WNDPROC>>> pre_wnd_proc;
|
|
||||||
};
|
};
|
129
src/modules/ShortcutGuide/ShortcutGuide/main.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <common/utils/window.h>
|
||||||
|
#include <common/SettingsAPI/settings_helpers.h>
|
||||||
|
#include <common/utils/ProcessWaiter.h>
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
|
#include <common/utils/UnhandledExceptionHandler_x64.h>
|
||||||
|
#include <common/utils/logger_helper.h>
|
||||||
|
#include <common/utils/EventWaiter.h>
|
||||||
|
|
||||||
|
#include "shortcut_guide.h"
|
||||||
|
#include "target_state.h"
|
||||||
|
#include "ShortcutGuideConstants.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
const std::wstring instanceMutexName = L"Local\\PowerToys_ShortcutGuide_InstanceMutex";
|
||||||
|
|
||||||
|
// set current path to the executable path
|
||||||
|
bool SetCurrentPath()
|
||||||
|
{
|
||||||
|
TCHAR buffer[MAX_PATH] = { 0 };
|
||||||
|
if (!GetModuleFileName(NULL, buffer, MAX_PATH))
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to get module path. {}", get_last_error_or_default(GetLastError()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PathRemoveFileSpec(buffer))
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to remove file from module path. {}", get_last_error_or_default(GetLastError()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code err;
|
||||||
|
std::filesystem::current_path(buffer, err);
|
||||||
|
if (err.value())
|
||||||
|
{
|
||||||
|
Logger::error("Failed to set current path. {}", err.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR lpCmdLine, _In_ int nCmdShow)
|
||||||
|
{
|
||||||
|
winrt::init_apartment();
|
||||||
|
LoggerHelpers::init_logger(ShortcutGuideConstants::ModuleKey, L"ShortcutGuide", LogSettings::shortcutGuideLoggerName);
|
||||||
|
InitUnhandledExceptionHandler_x64();
|
||||||
|
Logger::trace("Starting Shortcut Guide");
|
||||||
|
|
||||||
|
if (!SetCurrentPath())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace::RegisterProvider();
|
||||||
|
if (std::wstring(lpCmdLine).find(L' ') != std::wstring::npos)
|
||||||
|
{
|
||||||
|
Logger::trace("Sending settings telemetry");
|
||||||
|
auto settings = OverlayWindow::GetSettings();
|
||||||
|
Trace::SendSettings(settings);
|
||||||
|
Trace::UnregisterProvider();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mutex = CreateMutex(nullptr, true, instanceMutexName.c_str());
|
||||||
|
if (mutex == nullptr)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to create mutex. {}", get_last_error_or_default(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||||
|
{
|
||||||
|
Logger::warn(L"Shortcut Guide instance is already running");
|
||||||
|
Trace::UnregisterProvider();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring pid = std::wstring(lpCmdLine);
|
||||||
|
if (!pid.empty())
|
||||||
|
{
|
||||||
|
auto mainThreadId = GetCurrentThreadId();
|
||||||
|
ProcessWaiter::OnProcessTerminate(pid, [mainThreadId](int err) {
|
||||||
|
if (err != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to wait for parent process exit. {}", get_last_error_or_default(err));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::trace(L"PowerToys runner exited.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::trace(L"Exiting Shortcut Guide");
|
||||||
|
PostThreadMessage(mainThreadId, WM_QUIT, 0, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hwnd = GetForegroundWindow();
|
||||||
|
auto window = OverlayWindow(hwnd);
|
||||||
|
EventWaiter exitEventWaiter;
|
||||||
|
if (window.IsDisabled())
|
||||||
|
{
|
||||||
|
Logger::trace("SG is disabled for the current foreground app. Exiting SG");
|
||||||
|
Trace::UnregisterProvider();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto mainThreadId = GetCurrentThreadId();
|
||||||
|
exitEventWaiter = EventWaiter(CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT, [mainThreadId, &window](int err) {
|
||||||
|
if (err != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to wait for {} event. {}", CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT, get_last_error_or_default(err));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::trace(L"{} event was signaled", CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.CloseWindow(HideWindowType::THE_SHORTCUT_PRESSED, mainThreadId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.ShowWindow();
|
||||||
|
run_message_loop();
|
||||||
|
Trace::UnregisterProvider();
|
||||||
|
return 0;
|
||||||
|
}
|
@ -6,7 +6,6 @@
|
|||||||
#include <common/utils/resources.h>
|
#include <common/utils/resources.h>
|
||||||
#include <common/utils/window.h>
|
#include <common/utils/window.h>
|
||||||
|
|
||||||
#include "keyboard_state.h"
|
|
||||||
#include "shortcut_guide.h"
|
#include "shortcut_guide.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "Generated Files/resource.h"
|
#include "Generated Files/resource.h"
|
||||||
@ -268,8 +267,8 @@ D2D1_RECT_F D2DOverlaySVG::get_snap_right() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
D2DOverlayWindow::D2DOverlayWindow(std::optional<std::function<std::remove_pointer_t<WNDPROC>>> pre_wnd_proc) :
|
D2DOverlayWindow::D2DOverlayWindow() :
|
||||||
total_screen({}), animation(0.3), D2DWindow(std::move(pre_wnd_proc))
|
total_screen({}), animation(0.3), D2DWindow()
|
||||||
{
|
{
|
||||||
tasklist_thread = std::thread([&] {
|
tasklist_thread = std::thread([&] {
|
||||||
while (running)
|
while (running)
|
||||||
@ -361,7 +360,6 @@ void D2DOverlayWindow::show(HWND active_window, bool snappable)
|
|||||||
shown_start_time = std::chrono::steady_clock::now();
|
shown_start_time = std::chrono::steady_clock::now();
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
D2DWindow::show(primary_screen.left(), primary_screen.top(), primary_screen.width(), primary_screen.height());
|
D2DWindow::show(primary_screen.left(), primary_screen.top(), primary_screen.width(), primary_screen.height());
|
||||||
key_pressed.clear();
|
|
||||||
// Check if taskbar is auto-hidden. If so, don't display the number arrows
|
// Check if taskbar is auto-hidden. If so, don't display the number arrows
|
||||||
APPBARDATA param = {};
|
APPBARDATA param = {};
|
||||||
param.cbSize = sizeof(APPBARDATA);
|
param.cbSize = sizeof(APPBARDATA);
|
||||||
@ -374,115 +372,6 @@ void D2DOverlayWindow::show(HWND active_window, bool snappable)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void D2DOverlayWindow::animate(int vk_code)
|
|
||||||
{
|
|
||||||
animate(vk_code, 0);
|
|
||||||
}
|
|
||||||
void D2DOverlayWindow::animate(int vk_code, int offset)
|
|
||||||
{
|
|
||||||
if (!initialized || !use_overlay)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool done = false;
|
|
||||||
for (auto& animation : key_animations)
|
|
||||||
{
|
|
||||||
if (animation.vk_code == vk_code)
|
|
||||||
{
|
|
||||||
animation.animation.reset(0.1, 0, 1);
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (done)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AnimateKeys animation;
|
|
||||||
std::wstring id;
|
|
||||||
animation.vk_code = vk_code;
|
|
||||||
winrt::com_ptr<ID2D1SvgElement> button_letter, parent;
|
|
||||||
if (vk_code >= 0x41 && vk_code <= 0x5A)
|
|
||||||
{
|
|
||||||
id.push_back('A' + (vk_code - 0x41));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (vk_code)
|
|
||||||
{
|
|
||||||
case VK_SNAPSHOT:
|
|
||||||
case VK_PRINT:
|
|
||||||
id = L"PrnScr";
|
|
||||||
break;
|
|
||||||
case VK_CONTROL:
|
|
||||||
case VK_LCONTROL:
|
|
||||||
case VK_RCONTROL:
|
|
||||||
id = L"Ctrl";
|
|
||||||
break;
|
|
||||||
case VK_UP:
|
|
||||||
id = L"KeyUp";
|
|
||||||
break;
|
|
||||||
case VK_LEFT:
|
|
||||||
id = L"KeyLeft";
|
|
||||||
break;
|
|
||||||
case VK_DOWN:
|
|
||||||
id = L"KeyDown";
|
|
||||||
break;
|
|
||||||
case VK_RIGHT:
|
|
||||||
id = L"KeyRight";
|
|
||||||
break;
|
|
||||||
case VK_OEM_PLUS:
|
|
||||||
case VK_ADD:
|
|
||||||
id = L"KeyPlus";
|
|
||||||
break;
|
|
||||||
case VK_OEM_MINUS:
|
|
||||||
case VK_SUBTRACT:
|
|
||||||
id = L"KeyMinus";
|
|
||||||
break;
|
|
||||||
case VK_TAB:
|
|
||||||
id = L"Tab";
|
|
||||||
break;
|
|
||||||
case VK_RETURN:
|
|
||||||
id = L"Enter";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset > 0)
|
|
||||||
{
|
|
||||||
id += L"_" + std::to_wstring(offset);
|
|
||||||
}
|
|
||||||
button_letter = use_overlay->find_element(id);
|
|
||||||
if (!button_letter)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
button_letter->GetParent(parent.put());
|
|
||||||
if (!parent)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parent->GetPreviousChild(button_letter.get(), animation.button.put());
|
|
||||||
if (!animation.button || !animation.button->IsAttributeSpecified(L"fill"))
|
|
||||||
{
|
|
||||||
animation.button = nullptr;
|
|
||||||
parent->GetNextChild(button_letter.get(), animation.button.put());
|
|
||||||
}
|
|
||||||
if (!animation.button || !animation.button->IsAttributeSpecified(L"fill"))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
winrt::com_ptr<ID2D1SvgPaint> paint;
|
|
||||||
animation.button->GetAttributeValue(L"fill", paint.put());
|
|
||||||
paint->GetColor(&animation.original);
|
|
||||||
animate(vk_code, offset + 1);
|
|
||||||
std::unique_lock lock(mutex);
|
|
||||||
animation.animation.reset(0.1, 0, 1);
|
|
||||||
key_animations.push_back(animation);
|
|
||||||
key_pressed.push_back(vk_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
void D2DOverlayWindow::on_show()
|
void D2DOverlayWindow::on_show()
|
||||||
{
|
{
|
||||||
// show override does everything
|
// show override does everything
|
||||||
@ -490,6 +379,7 @@ void D2DOverlayWindow::on_show()
|
|||||||
|
|
||||||
void D2DOverlayWindow::on_hide()
|
void D2DOverlayWindow::on_hide()
|
||||||
{
|
{
|
||||||
|
Logger::trace("D2DOverlayWindow::on_hide()");
|
||||||
tasklist_cv_mutex.lock();
|
tasklist_cv_mutex.lock();
|
||||||
tasklist_update = false;
|
tasklist_update = false;
|
||||||
tasklist_cv_mutex.unlock();
|
tasklist_cv_mutex.unlock();
|
||||||
@ -502,10 +392,11 @@ void D2DOverlayWindow::on_hide()
|
|||||||
// Trace the event only if the overlay window was visible.
|
// Trace the event only if the overlay window was visible.
|
||||||
if (shown_start_time.time_since_epoch().count() > 0)
|
if (shown_start_time.time_since_epoch().count() > 0)
|
||||||
{
|
{
|
||||||
Trace::HideGuide(std::chrono::duration_cast<std::chrono::milliseconds>(shown_end_time - shown_start_time).count(), key_pressed);
|
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(shown_end_time - shown_start_time).count();
|
||||||
|
Logger::trace(L"Duration: {}. Close Type: {}", duration, windowCloseType);
|
||||||
|
Trace::SendGuideSession(duration, windowCloseType.c_str());
|
||||||
shown_start_time = {};
|
shown_start_time = {};
|
||||||
}
|
}
|
||||||
key_pressed.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D2DOverlayWindow::~D2DOverlayWindow()
|
D2DOverlayWindow::~D2DOverlayWindow()
|
||||||
@ -758,6 +649,11 @@ void D2DOverlayWindow::render(ID2D1DeviceContext5* d2d_dc)
|
|||||||
// Thumbnail logic:
|
// Thumbnail logic:
|
||||||
auto window_state = get_window_state(active_window);
|
auto window_state = get_window_state(active_window);
|
||||||
auto thumb_window = get_window_pos(active_window);
|
auto thumb_window = get_window_pos(active_window);
|
||||||
|
if (!thumb_window.has_value())
|
||||||
|
{
|
||||||
|
thumb_window = RECT();
|
||||||
|
}
|
||||||
|
|
||||||
bool miniature_shown = active_window != nullptr && thumbnail != nullptr && thumb_window && window_state != MINIMIZED;
|
bool miniature_shown = active_window != nullptr && thumbnail != nullptr && thumb_window && window_state != MINIMIZED;
|
||||||
RECT client_rect;
|
RECT client_rect;
|
||||||
if (thumb_window && GetClientRect(active_window, &client_rect))
|
if (thumb_window && GetClientRect(active_window, &client_rect))
|
@ -47,18 +47,21 @@ struct AnimateKeys
|
|||||||
class D2DOverlayWindow : public D2DWindow
|
class D2DOverlayWindow : public D2DWindow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
D2DOverlayWindow(std::optional<std::function<std::remove_pointer_t<WNDPROC>>> pre_wnd_proc = std::nullopt);
|
D2DOverlayWindow();
|
||||||
void show(HWND active_window, bool snappable);
|
void show(HWND active_window, bool snappable);
|
||||||
void animate(int vk_code);
|
|
||||||
~D2DOverlayWindow();
|
~D2DOverlayWindow();
|
||||||
void apply_overlay_opacity(float opacity);
|
void apply_overlay_opacity(float opacity);
|
||||||
void set_theme(const std::wstring& theme);
|
void set_theme(const std::wstring& theme);
|
||||||
void quick_hide();
|
void quick_hide();
|
||||||
|
|
||||||
HWND get_window_handle();
|
HWND get_window_handle();
|
||||||
|
void SetWindowCloseType(std::wstring windowCloseType)
|
||||||
|
{
|
||||||
|
this->windowCloseType = windowCloseType;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void animate(int vk_code, int offset);
|
std::wstring windowCloseType;
|
||||||
bool show_thumbnail(const RECT& rect, double alpha);
|
bool show_thumbnail(const RECT& rect, double alpha);
|
||||||
void hide_thumbnail();
|
void hide_thumbnail();
|
||||||
virtual void init() override;
|
virtual void init() override;
|
||||||
@ -70,7 +73,6 @@ private:
|
|||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
std::vector<AnimateKeys> key_animations;
|
std::vector<AnimateKeys> key_animations;
|
||||||
std::vector<int> key_pressed;
|
|
||||||
std::vector<MonitorInfo> monitors;
|
std::vector<MonitorInfo> monitors;
|
||||||
ScreenSize total_screen;
|
ScreenSize total_screen;
|
||||||
int monitor_dx = 0, monitor_dy = 0;
|
int monitor_dx = 0, monitor_dy = 0;
|
@ -1 +1 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
@ -1,29 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#include <winrt/base.h>
|
#include <winrt/base.h>
|
||||||
#include <winrt/Windows.Foundation.h>
|
#include <winrt/Windows.Foundation.h>
|
||||||
#include <winrt/Windows.Foundation.Collections.h>
|
#include <winrt/Windows.Foundation.Collections.h>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <dxgi1_3.h>
|
#include <dxgi1_3.h>
|
||||||
#include <d3d11_2.h>
|
#include <d3d11_2.h>
|
||||||
#include <d2d1_3.h>
|
#include <d2d1_3.h>
|
||||||
#include <d2d1_3helper.h>
|
#include <d2d1_3helper.h>
|
||||||
#include <d2d1helper.h>
|
#include <d2d1helper.h>
|
||||||
#include <dwrite.h>
|
#include <dwrite.h>
|
||||||
#include <dcomp.h>
|
#include <dcomp.h>
|
||||||
#include <dwmapi.h>
|
#include <dwmapi.h>
|
||||||
#include <Shobjidl.h>
|
#include <Shobjidl.h>
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ProjectTelemetry.h>
|
#include <ProjectTelemetry.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <common/logger/logger.h>
|
13
src/modules/ShortcutGuide/ShortcutGuide/resource.base.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//{{NO_DEPENDENCIES}}
|
||||||
|
// Microsoft Visual C++ generated include file.
|
||||||
|
// Used by ShortcutGuide.rc
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
// Non-localizable
|
||||||
|
|
||||||
|
#define FILE_DESCRIPTION "PowerToys ShortcutGuide"
|
||||||
|
#define INTERNAL_NAME "ShortcutGuide"
|
||||||
|
#define ORIGINAL_FILENAME "PowerToys.ShortcutGuide.exe"
|
||||||
|
|
||||||
|
// Non-localizable
|
||||||
|
//////////////////////////////
|
419
src/modules/ShortcutGuide/ShortcutGuide/shortcut_guide.cpp
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "shortcut_guide.h"
|
||||||
|
#include "target_state.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
|
#include <common/debug_control.h>
|
||||||
|
#include <common/interop/shared_constants.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <common/SettingsAPI/settings_helpers.h>
|
||||||
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
|
#include <common/logger/logger.h>
|
||||||
|
#include <common/utils/process_path.h>
|
||||||
|
#include <common/utils/resources.h>
|
||||||
|
#include <common/utils/string_utils.h>
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
|
#include <common/utils/window.h>
|
||||||
|
#include <Psapi.h>
|
||||||
|
#include <common/hooks/LowlevelKeyboardEvent.h>
|
||||||
|
|
||||||
|
// TODO: refactor singleton
|
||||||
|
OverlayWindow* instance = nullptr;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Window properties relevant to ShortcutGuide
|
||||||
|
struct ShortcutGuideWindowInfo
|
||||||
|
{
|
||||||
|
HWND hwnd = nullptr; // Handle to the top-level foreground window or nullptr if there is no such window
|
||||||
|
bool snappable = false; // True, if the window can react to Windows Snap keys
|
||||||
|
bool disabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ShortcutGuideWindowInfo GetShortcutGuideWindowInfo(HWND active_window)
|
||||||
|
{
|
||||||
|
ShortcutGuideWindowInfo result;
|
||||||
|
active_window = GetAncestor(active_window, GA_ROOT);
|
||||||
|
if (!IsWindowVisible(active_window))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto style = GetWindowLong(active_window, GWL_STYLE);
|
||||||
|
auto exStyle = GetWindowLong(active_window, GWL_EXSTYLE);
|
||||||
|
if ((style & WS_CHILD) == WS_CHILD ||
|
||||||
|
(style & WS_DISABLED) == WS_DISABLED ||
|
||||||
|
(exStyle & WS_EX_TOOLWINDOW) == WS_EX_TOOLWINDOW ||
|
||||||
|
(exStyle & WS_EX_NOACTIVATE) == WS_EX_NOACTIVATE)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
std::array<char, 256> class_name;
|
||||||
|
GetClassNameA(active_window, class_name.data(), static_cast<int>(class_name.size()));
|
||||||
|
if (is_system_window(active_window, class_name.data()))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
static HWND cortana_hwnd = nullptr;
|
||||||
|
if (cortana_hwnd == nullptr)
|
||||||
|
{
|
||||||
|
if (strcmp(class_name.data(), "Windows.UI.Core.CoreWindow") == 0 &&
|
||||||
|
get_process_path(active_window).ends_with(L"SearchUI.exe"))
|
||||||
|
{
|
||||||
|
cortana_hwnd = active_window;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cortana_hwnd == active_window)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.hwnd = active_window;
|
||||||
|
// In reality, Windows Snap works if even one of those styles is set
|
||||||
|
// for a window, it is just limited. If there is no WS_MAXIMIZEBOX using
|
||||||
|
// WinKey + Up just won't maximize the window. Similary, without
|
||||||
|
// WS_MINIMIZEBOX the window will not get minimized. A "Save As..." dialog
|
||||||
|
// is a example of such window - it can be snapped to both sides and to
|
||||||
|
// all screen corners, but will not get maximized nor minimized.
|
||||||
|
// For now, since ShortcutGuide can only disable entire "Windows Controls"
|
||||||
|
// group, we require that the window supports all the options.
|
||||||
|
result.snappable = ((style & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX) &&
|
||||||
|
((style & WS_MINIMIZEBOX) == WS_MINIMIZEBOX) &&
|
||||||
|
((style & WS_THICKFRAME) == WS_THICKFRAME);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LPARAM eventActivateWindow = 1;
|
||||||
|
|
||||||
|
bool wasWinPressed = false;
|
||||||
|
bool isWinPressed()
|
||||||
|
{
|
||||||
|
return (GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// all modifiers without win key
|
||||||
|
std::vector<int> modifierKeys = { VK_SHIFT, VK_LSHIFT, VK_RSHIFT, VK_CONTROL, VK_LCONTROL, VK_RCONTROL, VK_MENU, VK_LMENU, VK_RMENU };
|
||||||
|
|
||||||
|
// returns false if there are other modifiers pressed or win key isn' pressed
|
||||||
|
bool onlyWinPressed()
|
||||||
|
{
|
||||||
|
if (!isWinPressed())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto key : modifierKeys)
|
||||||
|
{
|
||||||
|
if (GetAsyncKeyState(key) & 0x8000)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isWin(int key)
|
||||||
|
{
|
||||||
|
return key == VK_LWIN || key == VK_RWIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isKeyDown(LowlevelKeyboardEvent event)
|
||||||
|
{
|
||||||
|
return event.wParam == WM_KEYDOWN || event.wParam == WM_SYSKEYDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
LowlevelKeyboardEvent event;
|
||||||
|
if (nCode == HC_ACTION)
|
||||||
|
{
|
||||||
|
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||||
|
event.wParam = wParam;
|
||||||
|
|
||||||
|
if (event.lParam->vkCode == VK_ESCAPE)
|
||||||
|
{
|
||||||
|
Logger::trace(L"ESC key was pressed");
|
||||||
|
instance->CloseWindow(HideWindowType::ESC_PRESSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wasWinPressed && !isKeyDown(event) && isWin(event.lParam->vkCode))
|
||||||
|
{
|
||||||
|
Logger::trace(L"Win key was released");
|
||||||
|
instance->CloseWindow(HideWindowType::WIN_RELEASED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isKeyDown(event) && isWin(event.lParam->vkCode))
|
||||||
|
{
|
||||||
|
wasWinPressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onlyWinPressed() && isKeyDown(event) && !isWin(event.lParam->vkCode))
|
||||||
|
{
|
||||||
|
Logger::trace(L"Shortcut with win key was pressed");
|
||||||
|
instance->CloseWindow(HideWindowType::WIN_SHORTCUT_PRESSED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring ToWstring(HideWindowType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case HideWindowType::ESC_PRESSED:
|
||||||
|
return L"ESC_PRESSED";
|
||||||
|
case HideWindowType::WIN_RELEASED:
|
||||||
|
return L"WIN_RELEASED";
|
||||||
|
case HideWindowType::WIN_SHORTCUT_PRESSED:
|
||||||
|
return L"WIN_SHORTCUT_PRESSED";
|
||||||
|
case HideWindowType::THE_SHORTCUT_PRESSED:
|
||||||
|
return L"THE_SHORTCUT_PRESSED";
|
||||||
|
}
|
||||||
|
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayWindow::OverlayWindow(HWND activeWindow)
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
this -> activeWindow = activeWindow;
|
||||||
|
app_name = GET_RESOURCE_STRING(IDS_SHORTCUT_GUIDE);
|
||||||
|
|
||||||
|
Logger::info("Overlay Window is creating");
|
||||||
|
init_settings();
|
||||||
|
keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), NULL);
|
||||||
|
if (!keyboardHook)
|
||||||
|
{
|
||||||
|
Logger::warn(L"Failed to create low level keyboard hook. {}", get_last_error_or_default(GetLastError()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::ShowWindow()
|
||||||
|
{
|
||||||
|
winkey_popup = std::make_unique<D2DOverlayWindow>();
|
||||||
|
winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value) / 100.0f);
|
||||||
|
winkey_popup->set_theme(theme.value);
|
||||||
|
target_state = std::make_unique<TargetState>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
winkey_popup->initialize();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Logger::critical("Winkey popup failed to initialize");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_state->toggle_force_shown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::CloseWindow(HideWindowType type, int mainThreadId)
|
||||||
|
{
|
||||||
|
if (mainThreadId == 0)
|
||||||
|
{
|
||||||
|
mainThreadId = GetCurrentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->winkey_popup)
|
||||||
|
{
|
||||||
|
this->winkey_popup->SetWindowCloseType(ToWstring(type));
|
||||||
|
Logger::trace(L"Terminating process");
|
||||||
|
PostThreadMessage(mainThreadId, WM_QUIT, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverlayWindow::IsDisabled()
|
||||||
|
{
|
||||||
|
WCHAR exePath[MAX_PATH] = L"";
|
||||||
|
instance->get_exe_path(activeWindow, exePath);
|
||||||
|
if (wcslen(exePath) > 0)
|
||||||
|
{
|
||||||
|
return is_disabled_app(exePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayWindow::~OverlayWindow()
|
||||||
|
{
|
||||||
|
if (event_waiter)
|
||||||
|
{
|
||||||
|
event_waiter.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (winkey_popup)
|
||||||
|
{
|
||||||
|
winkey_popup->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_state)
|
||||||
|
{
|
||||||
|
target_state->exit();
|
||||||
|
target_state.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (winkey_popup)
|
||||||
|
{
|
||||||
|
winkey_popup.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyboardHook)
|
||||||
|
{
|
||||||
|
UnhookWindowsHookEx(keyboardHook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::on_held()
|
||||||
|
{
|
||||||
|
auto windowInfo = GetShortcutGuideWindowInfo(activeWindow);
|
||||||
|
if (windowInfo.disabled)
|
||||||
|
{
|
||||||
|
target_state->was_hidden();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
winkey_popup->show(windowInfo.hwnd, windowInfo.snappable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::quick_hide()
|
||||||
|
{
|
||||||
|
winkey_popup->quick_hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::was_hidden()
|
||||||
|
{
|
||||||
|
target_state->was_hidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverlayWindow::overlay_visible() const
|
||||||
|
{
|
||||||
|
return target_state->active();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::init_settings()
|
||||||
|
{
|
||||||
|
auto settings = GetSettings();
|
||||||
|
overlayOpacity.value = settings.overlayOpacity;
|
||||||
|
theme.value = settings.theme;
|
||||||
|
disabledApps.value = settings.disabledApps;
|
||||||
|
update_disabled_apps();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverlayWindow::is_disabled_app(wchar_t* exePath)
|
||||||
|
{
|
||||||
|
if (exePath == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto exePathUpper = std::wstring(exePath);
|
||||||
|
CharUpperBuffW(exePathUpper.data(), (DWORD)exePathUpper.length());
|
||||||
|
for (const auto& row : disabled_apps_array)
|
||||||
|
{
|
||||||
|
const auto pos = exePathUpper.rfind(row);
|
||||||
|
const auto last_slash = exePathUpper.rfind('\\');
|
||||||
|
// Check that row occurs in disabled_apps_array, and its last occurrence contains in itself the first character after the last backslash.
|
||||||
|
if (pos != std::wstring::npos && pos <= last_slash + 1 && pos + row.length() > last_slash)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::update_disabled_apps()
|
||||||
|
{
|
||||||
|
disabled_apps_array.clear();
|
||||||
|
auto disabledUppercase = disabledApps.value;
|
||||||
|
CharUpperBuffW(disabledUppercase.data(), (DWORD)disabledUppercase.length());
|
||||||
|
std::wstring_view view(disabledUppercase);
|
||||||
|
view = trim(view);
|
||||||
|
while (!view.empty())
|
||||||
|
{
|
||||||
|
auto pos = (std::min)(view.find_first_of(L"\r\n"), view.length());
|
||||||
|
disabled_apps_array.emplace_back(view.substr(0, pos));
|
||||||
|
view.remove_prefix(pos);
|
||||||
|
view = trim(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWindow::get_exe_path(HWND window, wchar_t* path)
|
||||||
|
{
|
||||||
|
if (disabled_apps_array.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD pid = 0;
|
||||||
|
GetWindowThreadProcessId(window, &pid);
|
||||||
|
if (pid != 0)
|
||||||
|
{
|
||||||
|
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||||
|
if (processHandle && GetProcessImageFileName(processHandle, path, MAX_PATH) > 0)
|
||||||
|
{
|
||||||
|
CloseHandle(processHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortcutGuideSettings OverlayWindow::GetSettings() noexcept
|
||||||
|
{
|
||||||
|
ShortcutGuideSettings settings;
|
||||||
|
json::JsonObject properties;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PowerToysSettings::PowerToyValues settingsValues =
|
||||||
|
PowerToysSettings::PowerToyValues::load_from_settings_file(app_key);
|
||||||
|
|
||||||
|
auto settingsObject = settingsValues.get_raw_json();
|
||||||
|
if (!settingsObject.GetView().Size())
|
||||||
|
{
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties = settingsObject.GetNamedObject(L"properties");
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Logger::warn("Failed to read settings. Use default settings");
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
settings.hotkey = PowerToysSettings::HotkeyObject::from_json(properties.GetNamedObject(OpenShortcut::name)).to_string();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
settings.overlayOpacity = (int)properties.GetNamedObject(OverlayOpacity::name).GetNamedNumber(L"value");
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
settings.theme = (std::wstring)properties.GetNamedObject(Theme::name).GetNamedString(L"value");
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
settings.disabledApps = (std::wstring)properties.GetNamedObject(DisabledApps::name).GetNamedString(L"value");
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
@ -1,90 +1,85 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <interface/powertoy_module_interface.h>
|
#include "../interface/powertoy_module_interface.h"
|
||||||
#include "overlay_window.h"
|
//#include <interface/powertoy_module_interface.h>
|
||||||
#include "native_event_waiter.h"
|
#include "overlay_window.h"
|
||||||
|
#include "native_event_waiter.h"
|
||||||
#include "Generated Files/resource.h"
|
#include "ShortcutGuideSettings.h"
|
||||||
|
#include "ShortcutGuideConstants.h"
|
||||||
#include <common/hooks/LowlevelKeyboardEvent.h>
|
|
||||||
|
#include "Generated Files/resource.h"
|
||||||
// We support only one instance of the overlay
|
|
||||||
extern class OverlayWindow* instance;
|
// We support only one instance of the overlay
|
||||||
|
extern class OverlayWindow* instance;
|
||||||
class TargetState;
|
|
||||||
|
class TargetState;
|
||||||
class OverlayWindow : public PowertoyModuleIface
|
|
||||||
{
|
enum class HideWindowType
|
||||||
public:
|
{
|
||||||
OverlayWindow();
|
ESC_PRESSED,
|
||||||
|
WIN_RELEASED,
|
||||||
virtual const wchar_t* get_name() override;
|
WIN_SHORTCUT_PRESSED,
|
||||||
virtual const wchar_t* get_key() override;
|
THE_SHORTCUT_PRESSED
|
||||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override;
|
};
|
||||||
|
|
||||||
virtual void set_config(const wchar_t* config) override;
|
class OverlayWindow
|
||||||
virtual void enable() override;
|
{
|
||||||
virtual void disable() override;
|
public:
|
||||||
virtual bool is_enabled() override;
|
OverlayWindow(HWND activeWindow);
|
||||||
|
void ShowWindow();
|
||||||
void on_held();
|
void CloseWindow(HideWindowType type, int mainThreadId = 0);
|
||||||
void on_held_press(DWORD vkCode);
|
bool IsDisabled();
|
||||||
void quick_hide();
|
|
||||||
void was_hidden();
|
void on_held();
|
||||||
|
void quick_hide();
|
||||||
intptr_t signal_event(LowlevelKeyboardEvent* event);
|
void was_hidden();
|
||||||
|
|
||||||
virtual void destroy() override;
|
bool overlay_visible() const;
|
||||||
|
|
||||||
bool overlay_visible() const;
|
bool is_disabled_app(wchar_t* exePath);
|
||||||
|
|
||||||
bool is_disabled_app(wchar_t* exePath);
|
void get_exe_path(HWND window, wchar_t* exePath);
|
||||||
|
~OverlayWindow();
|
||||||
void get_exe_path(HWND window, wchar_t* exePath);
|
static ShortcutGuideSettings GetSettings() noexcept;
|
||||||
|
private:
|
||||||
private:
|
std::wstring app_name;
|
||||||
std::wstring app_name;
|
//contains the non localized key of the powertoy
|
||||||
//contains the non localized key of the powertoy
|
static inline std::wstring app_key = ShortcutGuideConstants::ModuleKey;
|
||||||
std::wstring app_key;
|
std::unique_ptr<TargetState> target_state;
|
||||||
std::unique_ptr<TargetState> target_state;
|
std::unique_ptr<D2DOverlayWindow> winkey_popup;
|
||||||
std::unique_ptr<D2DOverlayWindow> winkey_popup;
|
std::unique_ptr<NativeEventWaiter> event_waiter;
|
||||||
bool _enabled = false;
|
std::vector<std::wstring> disabled_apps_array;
|
||||||
HHOOK hook_handle;
|
void init_settings();
|
||||||
std::unique_ptr<NativeEventWaiter> event_waiter;
|
void update_disabled_apps();
|
||||||
std::vector<std::wstring> disabled_apps_array;
|
HWND activeWindow;
|
||||||
|
HHOOK keyboardHook;
|
||||||
void init_settings();
|
|
||||||
void disable(bool trace_event);
|
struct OverlayOpacity
|
||||||
void update_disabled_apps();
|
{
|
||||||
|
static inline PCWSTR name = L"overlay_opacity";
|
||||||
struct PressTime
|
int value;
|
||||||
{
|
int resourceId = IDS_SETTING_DESCRIPTION_OVERLAY_OPACITY;
|
||||||
PCWSTR name = L"press_time";
|
} overlayOpacity;
|
||||||
int value = 900; // ms
|
|
||||||
int resourceId = IDS_SETTING_DESCRIPTION_PRESS_TIME;
|
struct Theme
|
||||||
} pressTime;
|
{
|
||||||
|
static inline PCWSTR name = L"theme";
|
||||||
struct OverlayOpacity
|
std::wstring value;
|
||||||
{
|
int resourceId = IDS_SETTING_DESCRIPTION_THEME;
|
||||||
PCWSTR name = L"overlay_opacity";
|
std::vector<std::pair<std::wstring, UINT>> keys_and_texts = {
|
||||||
int value = 90; // percent
|
{ L"system", IDS_SETTING_DESCRIPTION_THEME_SYSTEM },
|
||||||
int resourceId = IDS_SETTING_DESCRIPTION_OVERLAY_OPACITY;
|
{ L"light", IDS_SETTING_DESCRIPTION_THEME_LIGHT },
|
||||||
} overlayOpacity;
|
{ L"dark", IDS_SETTING_DESCRIPTION_THEME_DARK }
|
||||||
|
};
|
||||||
struct Theme
|
} theme;
|
||||||
{
|
|
||||||
PCWSTR name = L"theme";
|
struct DisabledApps
|
||||||
std::wstring value = L"system";
|
{
|
||||||
int resourceId = IDS_SETTING_DESCRIPTION_THEME;
|
static inline PCWSTR name = L"disabled_apps";
|
||||||
std::vector<std::pair<std::wstring, UINT>> keys_and_texts = {
|
std::wstring value;
|
||||||
{ L"system", IDS_SETTING_DESCRIPTION_THEME_SYSTEM },
|
} disabledApps;
|
||||||
{ L"light", IDS_SETTING_DESCRIPTION_THEME_LIGHT },
|
|
||||||
{ L"dark", IDS_SETTING_DESCRIPTION_THEME_DARK }
|
struct OpenShortcut
|
||||||
};
|
{
|
||||||
} theme;
|
static inline PCWSTR name = L"open_shortcutguide";
|
||||||
|
} openShortcut;
|
||||||
struct DisabledApps
|
};
|
||||||
{
|
|
||||||
PCWSTR name = L"disabled_apps";
|
|
||||||
std::wstring value = L"";
|
|
||||||
} disabledApps;
|
|
||||||
};
|
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 362 KiB After Width: | Height: | Size: 362 KiB |
Before Width: | Height: | Size: 368 KiB After Width: | Height: | Size: 368 KiB |
47
src/modules/ShortcutGuide/ShortcutGuide/target_state.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "target_state.h"
|
||||||
|
#include "start_visible.h"
|
||||||
|
#include <common/interop/shared_constants.h>
|
||||||
|
#include <common/logger/logger.h>
|
||||||
|
|
||||||
|
constexpr unsigned VK_S = 0x53;
|
||||||
|
|
||||||
|
void TargetState::was_hidden()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::recursive_mutex> lock(mutex);
|
||||||
|
// Ignore callbacks from the D2DOverlayWindow
|
||||||
|
if (state == ForceShown)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state = Hidden;
|
||||||
|
lock.unlock();
|
||||||
|
cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TargetState::exit()
|
||||||
|
{
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
state = Exiting;
|
||||||
|
lock.unlock();
|
||||||
|
cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TargetState::toggle_force_shown()
|
||||||
|
{
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
if (state != ForceShown)
|
||||||
|
{
|
||||||
|
state = ForceShown;
|
||||||
|
instance->on_held();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = Hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TargetState::active() const
|
||||||
|
{
|
||||||
|
return state == ForceShown || state == Shown;
|
||||||
|
}
|
33
src/modules/ShortcutGuide/ShortcutGuide/target_state.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include "shortcut_guide.h"
|
||||||
|
|
||||||
|
struct KeyEvent
|
||||||
|
{
|
||||||
|
bool key_down;
|
||||||
|
unsigned vk_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TargetState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TargetState() = default;
|
||||||
|
void was_hidden();
|
||||||
|
void exit();
|
||||||
|
|
||||||
|
void toggle_force_shown();
|
||||||
|
bool active() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::recursive_mutex mutex;
|
||||||
|
std::condition_variable_any cv;
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
Hidden,
|
||||||
|
Shown,
|
||||||
|
ForceShown,
|
||||||
|
Exiting
|
||||||
|
};
|
||||||
|
std::atomic<State> state = Hidden;
|
||||||
|
};
|
45
src/modules/ShortcutGuide/ShortcutGuide/trace.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#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() noexcept
|
||||||
|
{
|
||||||
|
TraceLoggingRegister(g_hProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::UnregisterProvider() noexcept
|
||||||
|
{
|
||||||
|
TraceLoggingUnregister(g_hProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::SendGuideSession(const __int64 duration_ms, const wchar_t* close_type) noexcept
|
||||||
|
{
|
||||||
|
TraceLoggingWrite(
|
||||||
|
g_hProvider,
|
||||||
|
"ShortcutGuide_GuideSession",
|
||||||
|
TraceLoggingInt64(duration_ms, "DurationInMs"),
|
||||||
|
TraceLoggingWideString(close_type, "CloseType"),
|
||||||
|
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||||
|
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||||
|
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::SendSettings(ShortcutGuideSettings settings) noexcept
|
||||||
|
{
|
||||||
|
TraceLoggingWrite(
|
||||||
|
g_hProvider,
|
||||||
|
"ShortcutGuide_Settings",
|
||||||
|
TraceLoggingWideString(settings.hotkey.c_str(), "Hotkey"),
|
||||||
|
TraceLoggingInt32(settings.overlayOpacity, "OverlayOpacity"),
|
||||||
|
TraceLoggingWideString(settings.theme.c_str(), "Theme"),
|
||||||
|
TraceLoggingWideString(settings.disabledApps.c_str(), "DisabledApps"),
|
||||||
|
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||||
|
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||||
|
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||||
|
}
|
11
src/modules/ShortcutGuide/ShortcutGuide/trace.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ShortcutGuideSettings.h"
|
||||||
|
|
||||||
|
class Trace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void RegisterProvider() noexcept;
|
||||||
|
static void UnregisterProvider() noexcept;
|
||||||
|
static void SendGuideSession(const __int64 duration_ms, const wchar_t* close_type) noexcept;
|
||||||
|
static void SendSettings(ShortcutGuideSettings settings) noexcept;
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"Projects": [
|
||||||
|
{
|
||||||
|
"LanguageSet": "Azure_Languages",
|
||||||
|
"LocItems": [
|
||||||
|
{
|
||||||
|
"SourceFile": "src\\modules\\ShortcutGuide\\ShortcutGuideModuleInterface\\Resources.resx",
|
||||||
|
"CopyOption": "LangIDOnName",
|
||||||
|
"OutputPath": "src\\modules\\ShortcutGuide\\ShortcutGuideModuleInterface"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Shortcut_Guide" xml:space="preserve">
|
||||||
|
<value>Shortcut Guide</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
@ -0,0 +1,45 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include "Generated Files/resource.h"
|
||||||
|
#include "../../../../common/version/version.h"
|
||||||
|
|
||||||
|
#define APSTUDIO_READONLY_SYMBOLS
|
||||||
|
#include "winres.h"
|
||||||
|
#undef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Version
|
||||||
|
//
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION FILE_VERSION
|
||||||
|
PRODUCTVERSION PRODUCT_VERSION
|
||||||
|
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS VS_FF_DEBUG
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS VOS_NT_WINDOWS32
|
||||||
|
FILETYPE VFT_DLL
|
||||||
|
FILESUBTYPE VFT2_UNKNOWN
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", COMPANY_NAME
|
||||||
|
VALUE "FileDescription", FILE_DESCRIPTION
|
||||||
|
VALUE "FileVersion", FILE_VERSION_STRING
|
||||||
|
VALUE "InternalName", INTERNAL_NAME
|
||||||
|
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||||
|
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||||
|
VALUE "ProductName", PRODUCT_NAME
|
||||||
|
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
@ -1,133 +1,103 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" 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')" />
|
<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">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>x64</Platform>
|
<Platform>x64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|x64">
|
<ProjectConfiguration Include="Release|x64">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>x64</Platform>
|
<Platform>x64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
|
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
|
||||||
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h shortcut_guide.base.rc shortcut_guide.rc" />
|
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h ShortcutGuideModuleInterface.base.rc ShortcutGuideModuleInterface.rc" />
|
||||||
</Target>
|
</Target>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<VCProjectVersion>15.0</VCProjectVersion>
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
<ProjectGuid>{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}</ProjectGuid>
|
<Keyword>Win32Proj</Keyword>
|
||||||
<Keyword>Win32Proj</Keyword>
|
<ProjectGuid>{2d604c07-51fc-46bb-9eb7-75aecc7f5e81}</ProjectGuid>
|
||||||
<RootNamespace>overlaywindow</RootNamespace>
|
<RootNamespace>ShortcutGuideModuleInterface</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
|
||||||
<ProjectName>ShortcutGuide</ProjectName>
|
<ProjectName>ShortcutGuideModuleInterface</ProjectName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
<ImportGroup Label="ExtensionSettings">
|
<ImportGroup Label="ExtensionSettings">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="Shared">
|
<ImportGroup Label="Shared">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<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" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<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" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\$(ProjectName)\</OutDir>
|
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\ShortcutGuide\$(ProjectName)\</OutDir>
|
||||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\ShortcutGuide\$(ProjectName)\</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup>
|
<ItemDefinitionGroup>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalIncludeDirectories>..\..\common\inc;..\..\common\Telemetry;..\..\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\..\;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>Dwmapi.lib;Dcomp.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>Dwmapi.lib;Dcomp.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="animation.h" />
|
<ClInclude Include="Generated Files\resource.h" />
|
||||||
<ClInclude Include="d2d_svg.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="d2d_text.h" />
|
<ClInclude Include="resource.base.h" />
|
||||||
<ClInclude Include="d2d_window.h" />
|
</ItemGroup>
|
||||||
<ClInclude Include="native_event_waiter.h" />
|
<ItemGroup>
|
||||||
<ClInclude Include="overlay_window.h" />
|
<ClCompile Include="dllmain.cpp" />
|
||||||
<ClInclude Include="keyboard_state.h" />
|
<ClCompile Include="pch.cpp">
|
||||||
<ClInclude Include="Generated Files/resource.h" />
|
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||||
<None Include="resource.base.h" />
|
</ClCompile>
|
||||||
<ClInclude Include="ShortcutGuideConstants.h" />
|
</ItemGroup>
|
||||||
<ClInclude Include="shortcut_guide.h" />
|
<ItemGroup>
|
||||||
<ClInclude Include="pch.h" />
|
<None Include="packages.config" />
|
||||||
<ClInclude Include="start_visible.h" />
|
</ItemGroup>
|
||||||
<ClInclude Include="target_state.h" />
|
<ItemGroup>
|
||||||
<ClInclude Include="trace.h" />
|
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||||
</ItemGroup>
|
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||||
<ItemGroup>
|
</ProjectReference>
|
||||||
<ClCompile Include="animation.cpp" />
|
</ItemGroup>
|
||||||
<ClCompile Include="d2d_svg.cpp" />
|
<ItemGroup>
|
||||||
<ClCompile Include="d2d_text.cpp" />
|
<EmbeddedResource Include="Resources.resx" />
|
||||||
<ClCompile Include="d2d_window.cpp" />
|
</ItemGroup>
|
||||||
<ClCompile Include="native_event_waiter.cpp" />
|
<ItemGroup>
|
||||||
<ClCompile Include="overlay_window.cpp" />
|
<ResourceCompile Include="Generated Files\ShortcutGuideModuleInterface.rc" />
|
||||||
<ClCompile Include="dllmain.cpp" />
|
<None Include="ShortcutGuideModuleInterface.base.rc" />
|
||||||
<ClCompile Include="keyboard_state.cpp" />
|
</ItemGroup>
|
||||||
<ClCompile Include="shortcut_guide.cpp" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ClCompile Include="pch.cpp">
|
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ClCompile>
|
<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')" />
|
||||||
<ClCompile Include="start_visible.cpp" />
|
</ImportGroup>
|
||||||
<ClCompile Include="target_state.cpp" />
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
<ClCompile Include="tasklist_positions.cpp" />
|
<PropertyGroup>
|
||||||
<ClCompile Include="trace.cpp" />
|
<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>
|
||||||
</ItemGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<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'))" />
|
||||||
<ProjectReference Include="..\..\common\Display\Display.vcxproj">
|
<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'))" />
|
||||||
<Project>{caba8dfb-823b-4bf2-93ac-3f31984150d9}</Project>
|
</Target>
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\..\common\logger\logger.vcxproj">
|
|
||||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\..\common\Themes\Themes.vcxproj">
|
|
||||||
<Project>{98537082-0fdb-40de-abd8-0dc5a4269bab}</Project>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ResourceCompile Include="Generated Files/shortcut_guide.rc" />
|
|
||||||
<None Include="shortcut_guide.base.rc" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="packages.config" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Resources.resx" />
|
|
||||||
</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>
|
</Project>
|
@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Generated Files">
|
||||||
|
<UniqueIdentifier>{7008d2a1-37df-4ef1-8d2c-e27de2a1a181}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="pch.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="resource.base.h">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Generated Files\resource.h">
|
||||||
|
<Filter>Generated Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dllmain.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="pch.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
<None Include="ShortcutGuideModuleInterface.base.rc">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Resources.resx">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="Generated Files\ShortcutGuideModuleInterface.rc">
|
||||||
|
<Filter>Generated Files</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -0,0 +1,308 @@
|
|||||||
|
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <common/SettingsAPI/settings_helpers.h>
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
|
#include <common/utils/logger_helper.h>
|
||||||
|
#include <common/interop/shared_constants.h>
|
||||||
|
|
||||||
|
#include "../interface/powertoy_module_interface.h"
|
||||||
|
#include "Generated Files/resource.h"
|
||||||
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShortcutGuideModule : public PowertoyModuleIface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShortcutGuideModule()
|
||||||
|
{
|
||||||
|
app_name = GET_RESOURCE_STRING(IDS_SHORTCUT_GUIDE);
|
||||||
|
app_key = L"Shortcut Guide";
|
||||||
|
LoggerHelpers::init_logger(app_key, L"ModuleInterface", LogSettings::shortcutGuideLoggerName);
|
||||||
|
|
||||||
|
std::filesystem::path oldLogPath(PTSettingsHelper::get_module_save_folder_location(app_key));
|
||||||
|
oldLogPath.append("ShortcutGuideLogs");
|
||||||
|
LoggerHelpers::delete_old_log_folder(oldLogPath);
|
||||||
|
|
||||||
|
exitEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT);
|
||||||
|
if (!exitEvent)
|
||||||
|
{
|
||||||
|
Logger::warn(L"Failed to create {} event. {}", CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT, get_last_error_or_default(GetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
InitSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const wchar_t* get_name() override
|
||||||
|
{
|
||||||
|
return app_name.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const wchar_t* get_key() override
|
||||||
|
{
|
||||||
|
return app_key.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||||
|
{
|
||||||
|
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||||
|
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||||
|
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_config(const wchar_t* config) override
|
||||||
|
{
|
||||||
|
Logger::trace("set_config()");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Parse the input JSON string.
|
||||||
|
PowerToysSettings::PowerToyValues values =
|
||||||
|
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||||
|
|
||||||
|
ParseHotkey(values);
|
||||||
|
}
|
||||||
|
catch (std::exception ex)
|
||||||
|
{
|
||||||
|
Logger::error("Failed to parse settings. {}", ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void enable() override
|
||||||
|
{
|
||||||
|
Logger::info("Shortcut Guide is enabling");
|
||||||
|
|
||||||
|
if (!_enabled)
|
||||||
|
{
|
||||||
|
_enabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::warn("Shortcut guide is already enabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void disable() override
|
||||||
|
{
|
||||||
|
Logger::info("ShortcutGuideModule::disable()");
|
||||||
|
if (_enabled)
|
||||||
|
{
|
||||||
|
_enabled = false;
|
||||||
|
TerminateProcess();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::warn("Shortcut Guide is already disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool is_enabled() override
|
||||||
|
{
|
||||||
|
return _enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destroy() override
|
||||||
|
{
|
||||||
|
this->disable();
|
||||||
|
if (exitEvent)
|
||||||
|
{
|
||||||
|
CloseHandle(exitEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::optional<HotkeyEx> GetHotkeyEx() override
|
||||||
|
{
|
||||||
|
Logger::trace("GetHotkeyEx()");
|
||||||
|
return m_hotkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnHotkeyEx() override
|
||||||
|
{
|
||||||
|
Logger::trace("OnHotkeyEx()");
|
||||||
|
if (!_enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsProcessActive())
|
||||||
|
{
|
||||||
|
TerminateProcess();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_hProcess)
|
||||||
|
{
|
||||||
|
CloseHandle(m_hProcess);
|
||||||
|
m_hProcess = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void send_settings_telemetry() override
|
||||||
|
{
|
||||||
|
Logger::trace("Send settings telemetry");
|
||||||
|
if (!StartProcess(L"telemetry"))
|
||||||
|
{
|
||||||
|
Logger::error("Failed to create a process to send settings telemetry");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::wstring app_name;
|
||||||
|
//contains the non localized key of the powertoy
|
||||||
|
std::wstring app_key;
|
||||||
|
bool _enabled = false;
|
||||||
|
HANDLE m_hProcess = nullptr;
|
||||||
|
|
||||||
|
// Hotkey to invoke the module
|
||||||
|
HotkeyEx m_hotkey;
|
||||||
|
HANDLE exitEvent;
|
||||||
|
|
||||||
|
bool StartProcess(std::wstring args = L"")
|
||||||
|
{
|
||||||
|
if (exitEvent)
|
||||||
|
{
|
||||||
|
ResetEvent(exitEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||||
|
std::wstring executable_args = L"";
|
||||||
|
executable_args.append(std::to_wstring(powertoys_pid));
|
||||||
|
if (!args.empty())
|
||||||
|
{
|
||||||
|
executable_args.append(L" ");
|
||||||
|
executable_args.append(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||||
|
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||||
|
sei.lpFile = L"modules\\ShortcutGuide\\ShortcutGuide\\PowerToys.ShortcutGuide.exe";
|
||||||
|
sei.nShow = SW_SHOWNORMAL;
|
||||||
|
sei.lpParameters = executable_args.data();
|
||||||
|
if (ShellExecuteExW(&sei) == false)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to start SG process. {}", get_last_error_or_default(GetLastError()));
|
||||||
|
auto message = get_last_error_message(GetLastError());
|
||||||
|
if (message.has_value())
|
||||||
|
{
|
||||||
|
Logger::error(message.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::trace(L"Started SG process with pid={}", GetProcessId(sei.hProcess));
|
||||||
|
m_hProcess = sei.hProcess;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminateProcess()
|
||||||
|
{
|
||||||
|
if (m_hProcess)
|
||||||
|
{
|
||||||
|
if (WaitForSingleObject(m_hProcess, 0) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
if (exitEvent && SetEvent(exitEvent))
|
||||||
|
{
|
||||||
|
Logger::trace(L"Signaled {}", CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::warn(L"Failed to signal {}", CommonSharedConstants::SHORTCUT_GUIDE_EXIT_EVENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CloseHandle(m_hProcess);
|
||||||
|
m_hProcess = nullptr;
|
||||||
|
Logger::trace("SG process was already terminated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsProcessActive()
|
||||||
|
{
|
||||||
|
return m_hProcess && WaitForSingleObject(m_hProcess, 0) != WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PowerToysSettings::PowerToyValues settings =
|
||||||
|
PowerToysSettings::PowerToyValues::load_from_settings_file(app_key);
|
||||||
|
|
||||||
|
ParseHotkey(settings);
|
||||||
|
}
|
||||||
|
catch (std::exception ex)
|
||||||
|
{
|
||||||
|
Logger::error("Failed to init settings. {}", ex.what());
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
Logger::error("Failed to init settings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseHotkey(PowerToysSettings::PowerToyValues& settings)
|
||||||
|
{
|
||||||
|
auto settingsObject = settings.get_raw_json();
|
||||||
|
if (settingsObject.GetView().Size())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto jsonHotkeyObject = settingsObject.GetNamedObject(L"properties").GetNamedObject(L"open_shortcutguide");
|
||||||
|
auto hotkey = PowerToysSettings::HotkeyObject::from_json(jsonHotkeyObject);
|
||||||
|
m_hotkey = HotkeyEx();
|
||||||
|
if (hotkey.win_pressed())
|
||||||
|
{
|
||||||
|
m_hotkey.modifiersMask |= MOD_WIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hotkey.ctrl_pressed())
|
||||||
|
{
|
||||||
|
m_hotkey.modifiersMask |= MOD_CONTROL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hotkey.shift_pressed())
|
||||||
|
{
|
||||||
|
m_hotkey.modifiersMask |= MOD_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hotkey.alt_pressed())
|
||||||
|
{
|
||||||
|
m_hotkey.modifiersMask |= MOD_ALT;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_hotkey.vkCode = hotkey.get_code();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Logger::warn("Failed to initialize Shortcut Guide start shortcut");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::info("Shortcut Guide settings are empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_hotkey.modifiersMask)
|
||||||
|
{
|
||||||
|
Logger::info("Shortcut Guide is going to use default shortcut");
|
||||||
|
m_hotkey.modifiersMask = MOD_SHIFT | MOD_WIN;
|
||||||
|
m_hotkey.vkCode = VK_OEM_2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||||
|
{
|
||||||
|
return new ShortcutGuideModule();
|
||||||
|
}
|
@ -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>
|
@ -0,0 +1 @@
|
|||||||
|
#include "pch.h"
|
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <winrt/base.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <ProjectTelemetry.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <common/logger/logger.h>
|
||||||
|
#include <common/utils/resources.h>
|
@ -47,6 +47,12 @@ public:
|
|||||||
|
|
||||||
std::strong_ordering operator<=>(const Hotkey&) const = default;
|
std::strong_ordering operator<=>(const Hotkey&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HotkeyEx
|
||||||
|
{
|
||||||
|
WORD modifiersMask = 0;
|
||||||
|
WORD vkCode = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/* Returns the localized name of the PowerToy*/
|
/* Returns the localized name of the PowerToy*/
|
||||||
virtual const wchar_t* get_name() = 0;
|
virtual const wchar_t* get_name() = 0;
|
||||||
@ -78,6 +84,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual size_t get_hotkeys(Hotkey* buffer, size_t buffer_size) { return 0; }
|
virtual size_t get_hotkeys(Hotkey* buffer, size_t buffer_size) { return 0; }
|
||||||
|
|
||||||
|
virtual std::optional<HotkeyEx> GetHotkeyEx()
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnHotkeyEx()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/* Called when one of the registered hotkeys is pressed. Should return true
|
/* Called when one of the registered hotkeys is pressed. Should return true
|
||||||
* if the key press is to be swallowed.
|
* if the key press is to be swallowed.
|
||||||
*/
|
*/
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
|
||||||
#include "pch.h"
|
|
||||||
#include <mutex>
|
|
||||||
#include "shortcut_guide.h"
|
|
||||||
#include "overlay_window.h"
|
|
||||||
#include "trace.h"
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
|
||||||
{
|
|
||||||
if (!instance)
|
|
||||||
{
|
|
||||||
instance = new OverlayWindow();
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "keyboard_state.h"
|
|
||||||
|
|
||||||
bool winkey_held()
|
|
||||||
{
|
|
||||||
auto left = GetAsyncKeyState(VK_LWIN);
|
|
||||||
auto right = GetAsyncKeyState(VK_RWIN);
|
|
||||||
return (left & 0x8000) || (right & 0x8000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the VK code is in the range of valid keys.
|
|
||||||
// Some VK codes should not be checked because they would return
|
|
||||||
// false positives when checking if only the "Win" key is pressed.
|
|
||||||
constexpr bool should_check(int vk)
|
|
||||||
{
|
|
||||||
switch (vk)
|
|
||||||
{
|
|
||||||
case VK_CANCEL:
|
|
||||||
case VK_BACK:
|
|
||||||
case VK_TAB:
|
|
||||||
case VK_CLEAR:
|
|
||||||
case VK_ESCAPE:
|
|
||||||
case VK_APPS:
|
|
||||||
case VK_SLEEP:
|
|
||||||
case VK_NUMLOCK:
|
|
||||||
case VK_SCROLL:
|
|
||||||
case VK_OEM_102:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vk >= VK_SHIFT && vk <= VK_CAPITAL)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vk >= VK_SPACE && vk <= VK_HELP)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Digits
|
|
||||||
if (vk >= 0x30 && vk <= 0x39)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Letters
|
|
||||||
if (vk >= 0x41 && vk <= 0x5A)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vk >= VK_NUMPAD0 && vk <= VK_F24)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vk >= VK_LSHIFT && vk <= VK_LAUNCH_APP2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vk >= VK_OEM_1 && vk <= VK_OEM_3)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vk >= VK_OEM_4 && vk <= VK_OEM_8)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vk >= VK_ATTN && vk <= VK_OEM_CLEAR)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool only_winkey_key_held()
|
|
||||||
{
|
|
||||||
for (int vk = VK_CANCEL; vk <= VK_OEM_CLEAR; vk++)
|
|
||||||
{
|
|
||||||
if (should_check(vk))
|
|
||||||
{
|
|
||||||
if (GetAsyncKeyState(vk) & 0x8000)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
bool winkey_held();
|
|
||||||
bool only_winkey_key_held();
|
|
@ -1,41 +0,0 @@
|
|||||||
#include <windows.h>
|
|
||||||
⌀椀渀挀氀甀搀攀 ∀爀攀猀漀甀爀挀攀⸀栀∀ഀ<EFBFBD>
|
|
||||||
⌀椀渀挀氀甀搀攀 ∀⸀⸀⼀⸀⸀⼀⸀⸀⼀挀漀洀洀漀渀⼀瘀攀爀猀椀漀渀⼀瘀攀爀猀椀漀渀⸀栀∀ഀ<EFBFBD>
|
|
||||||
ഀ<EFBFBD>
|
|
||||||
⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
|
|
||||||
⌀椀渀挀氀甀搀攀 ∀眀椀渀爀攀猀⸀栀∀ഀ<EFBFBD>
|
|
||||||
⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
|
|
||||||
ഀ<EFBFBD>
|
|
||||||
嘀䔀刀匀䤀伀一䤀一䘀伀ഀ<EFBFBD>
|
|
||||||
䘀䤀䰀䔀嘀䔀刀匀䤀伀一 䘀䤀䰀䔀开嘀䔀刀匀䤀伀一ഀ<EFBFBD>
|
|
||||||
倀刀伀䐀唀䌀吀嘀䔀刀匀䤀伀一 倀刀伀䐀唀䌀吀开嘀䔀刀匀䤀伀一ഀ<EFBFBD>
|
|
||||||
䘀䤀䰀䔀䘀䰀䄀䜀匀䴀䄀匀䬀 嘀匀开䘀䘀䤀开䘀䤀䰀䔀䘀䰀䄀䜀匀䴀䄀匀䬀ഀ<EFBFBD>
|
|
||||||
⌀椀昀搀攀昀 开䐀䔀䈀唀䜀ഀ<EFBFBD>
|
|
||||||
䘀䤀䰀䔀䘀䰀䄀䜀匀 嘀匀开䘀䘀开䐀䔀䈀唀䜀ഀ<EFBFBD>
|
|
||||||
⌀攀氀猀攀ഀ<EFBFBD>
|
|
||||||
䘀䤀䰀䔀䘀䰀䄀䜀匀 砀 䰀ഀ<EFBFBD>
|
|
||||||
⌀攀渀搀椀昀ഀ<EFBFBD>
|
|
||||||
䘀䤀䰀䔀伀匀 嘀伀匀开一吀开圀䤀一䐀伀圀匀㌀㈀ഀ<EFBFBD>
|
|
||||||
䘀䤀䰀䔀吀夀倀䔀 嘀䘀吀开䐀䰀䰀ഀ<EFBFBD>
|
|
||||||
䘀䤀䰀䔀匀唀䈀吀夀倀䔀 嘀䘀吀㈀开唀一䬀一伀圀一 ഀ<EFBFBD>
|
|
||||||
䈀䔀䜀䤀一ഀ<EFBFBD>
|
|
||||||
䈀䰀伀䌀䬀 ∀匀琀爀椀渀最䘀椀氀攀䤀渀昀漀∀ഀ<EFBFBD>
|
|
||||||
䈀䔀䜀䤀一ഀ<EFBFBD>
|
|
||||||
䈀䰀伀䌀䬀 ∀ 㐀 㤀 㐀戀 ∀ ⼀⼀ 唀匀 䔀渀最氀椀猀栀 ⠀ 砀 㐀 㤀⤀Ⰰ 唀渀椀挀漀搀攀 ⠀ 砀 㐀䈀 ⤀ 挀栀愀爀猀攀琀ഀ<EFBFBD>
|
|
||||||
䈀䔀䜀䤀一ഀ<EFBFBD>
|
|
||||||
嘀䄀䰀唀䔀 ∀䌀漀洀瀀愀渀礀一愀洀攀∀Ⰰ 䌀伀䴀倀䄀一夀开一䄀䴀䔀ഀ<EFBFBD>
|
|
||||||
嘀䄀䰀唀䔀 ∀䘀椀氀攀䐀攀猀挀爀椀瀀琀椀漀渀∀Ⰰ 䘀䤀䰀䔀开䐀䔀匀䌀刀䤀倀吀䤀伀一ഀ<EFBFBD>
|
|
||||||
嘀䄀䰀唀䔀 ∀䘀椀氀攀嘀攀爀猀椀漀渀∀Ⰰ 䘀䤀䰀䔀开嘀䔀刀匀䤀伀一开匀吀刀䤀一䜀ഀ<EFBFBD>
|
|
||||||
嘀䄀䰀唀䔀 ∀䤀渀琀攀爀渀愀氀一愀洀攀∀Ⰰ 䤀一吀䔀刀一䄀䰀开一䄀䴀䔀ഀ<EFBFBD>
|
|
||||||
嘀䄀䰀唀䔀 ∀䰀攀最愀氀䌀漀瀀礀爀椀最栀琀∀Ⰰ 䌀伀倀夀刀䤀䜀䠀吀开一伀吀䔀ഀ<EFBFBD>
|
|
||||||
嘀䄀䰀唀䔀 ∀伀爀椀最椀渀愀氀䘀椀氀攀渀愀洀攀∀Ⰰ 伀刀䤀䜀䤀一䄀䰀开䘀䤀䰀䔀一䄀䴀䔀ഀ<EFBFBD>
|
|
||||||
嘀䄀䰀唀䔀 ∀倀爀漀搀甀挀琀一愀洀攀∀Ⰰ 倀刀伀䐀唀䌀吀开一䄀䴀䔀ഀ<EFBFBD>
|
|
||||||
嘀䄀䰀唀䔀 ∀倀爀漀搀甀挀琀嘀攀爀猀椀漀渀∀Ⰰ 倀刀伀䐀唀䌀吀开嘀䔀刀匀䤀伀一开匀吀刀䤀一䜀ഀ<EFBFBD>
|
|
||||||
䔀一䐀ഀ<EFBFBD>
|
|
||||||
䔀一䐀ഀ<EFBFBD>
|
|
||||||
䈀䰀伀䌀䬀 ∀嘀愀爀䘀椀氀攀䤀渀昀漀∀ഀ<EFBFBD>
|
|
||||||
䈀䔀䜀䤀一ഀ<EFBFBD>
|
|
||||||
嘀䄀䰀唀䔀 ∀吀爀愀渀猀氀愀琀椀漀渀∀Ⰰ 砀㐀 㤀Ⰰ ㈀ ⼀⼀ 唀匀 䔀渀最氀椀猀栀 ⠀ 砀 㐀 㤀⤀Ⰰ 唀渀椀挀漀搀攀 ⠀㈀ ⤀ 挀栀愀爀猀攀琀ഀ<EFBFBD>
|
|
||||||
䔀一䐀ഀ<EFBFBD>
|
|
||||||
䔀一䐀ഀ<EFBFBD>
|
|
||||||
<EFBFBD>
|
|
@ -1,487 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "shortcut_guide.h"
|
|
||||||
#include "target_state.h"
|
|
||||||
#include "trace.h"
|
|
||||||
|
|
||||||
#include <common/SettingsAPI/settings_objects.h>
|
|
||||||
#include <common/debug_control.h>
|
|
||||||
#include <common/interop/shared_constants.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <modules/shortcut_guide/ShortcutGuideConstants.h>
|
|
||||||
|
|
||||||
#include <common/SettingsAPI/settings_helpers.h>
|
|
||||||
#include <common/SettingsAPI/settings_objects.h>
|
|
||||||
#include <common/logger/logger.h>
|
|
||||||
#include <common/utils/process_path.h>
|
|
||||||
#include <common/utils/resources.h>
|
|
||||||
#include <common/utils/string_utils.h>
|
|
||||||
#include <common/utils/winapi_error.h>
|
|
||||||
#include <common/utils/window.h>
|
|
||||||
#include <Psapi.h>
|
|
||||||
// TODO: refactor singleton
|
|
||||||
OverlayWindow* instance = nullptr;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
LowlevelKeyboardEvent event;
|
|
||||||
if (nCode == HC_ACTION)
|
|
||||||
{
|
|
||||||
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
|
||||||
event.wParam = wParam;
|
|
||||||
if (instance->signal_event(&event) != 0)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Window properties relevant to ShortcutGuide
|
|
||||||
struct ShortcutGuideWindowInfo
|
|
||||||
{
|
|
||||||
HWND hwnd = nullptr; // Handle to the top-level foreground window or nullptr if there is no such window
|
|
||||||
bool snappable = false; // True, if the window can react to Windows Snap keys
|
|
||||||
bool disabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
ShortcutGuideWindowInfo GetShortcutGuideWindowInfo()
|
|
||||||
{
|
|
||||||
ShortcutGuideWindowInfo result;
|
|
||||||
auto active_window = GetForegroundWindow();
|
|
||||||
active_window = GetAncestor(active_window, GA_ROOT);
|
|
||||||
if (!IsWindowVisible(active_window))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
WCHAR exePath[MAX_PATH] = L"";
|
|
||||||
instance->get_exe_path(active_window, exePath);
|
|
||||||
if (wcslen(exePath) > 0)
|
|
||||||
{
|
|
||||||
result.disabled = instance->is_disabled_app(exePath);
|
|
||||||
if (result.disabled)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto style = GetWindowLong(active_window, GWL_STYLE);
|
|
||||||
auto exStyle = GetWindowLong(active_window, GWL_EXSTYLE);
|
|
||||||
if ((style & WS_CHILD) == WS_CHILD ||
|
|
||||||
(style & WS_DISABLED) == WS_DISABLED ||
|
|
||||||
(exStyle & WS_EX_TOOLWINDOW) == WS_EX_TOOLWINDOW ||
|
|
||||||
(exStyle & WS_EX_NOACTIVATE) == WS_EX_NOACTIVATE)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
std::array<char, 256> class_name;
|
|
||||||
GetClassNameA(active_window, class_name.data(), static_cast<int>(class_name.size()));
|
|
||||||
if (is_system_window(active_window, class_name.data()))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
static HWND cortana_hwnd = nullptr;
|
|
||||||
if (cortana_hwnd == nullptr)
|
|
||||||
{
|
|
||||||
if (strcmp(class_name.data(), "Windows.UI.Core.CoreWindow") == 0 &&
|
|
||||||
get_process_path(active_window).ends_with(L"SearchUI.exe"))
|
|
||||||
{
|
|
||||||
cortana_hwnd = active_window;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cortana_hwnd == active_window)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result.hwnd = active_window;
|
|
||||||
// In reality, Windows Snap works if even one of those styles is set
|
|
||||||
// for a window, it is just limited. If there is no WS_MAXIMIZEBOX using
|
|
||||||
// WinKey + Up just won't maximize the window. Similary, without
|
|
||||||
// WS_MINIMIZEBOX the window will not get minimized. A "Save As..." dialog
|
|
||||||
// is a example of such window - it can be snapped to both sides and to
|
|
||||||
// all screen corners, but will not get maximized nor minimized.
|
|
||||||
// For now, since ShortcutGuide can only disable entire "Windows Controls"
|
|
||||||
// group, we require that the window supports all the options.
|
|
||||||
result.snappable = ((style & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX) &&
|
|
||||||
((style & WS_MINIMIZEBOX) == WS_MINIMIZEBOX) &&
|
|
||||||
((style & WS_THICKFRAME) == WS_THICKFRAME);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LPARAM eventActivateWindow = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
OverlayWindow::OverlayWindow()
|
|
||||||
{
|
|
||||||
app_name = GET_RESOURCE_STRING(IDS_SHORTCUT_GUIDE);
|
|
||||||
app_key = ShortcutGuideConstants::ModuleKey;
|
|
||||||
std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(app_key));
|
|
||||||
logFilePath.append(LogSettings::shortcutGuideLogPath);
|
|
||||||
Logger::init(LogSettings::shortcutGuideLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
|
|
||||||
Logger::info("Overlay Window is creating");
|
|
||||||
init_settings();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the localized display name of the powertoy
|
|
||||||
const wchar_t* OverlayWindow::get_name()
|
|
||||||
{
|
|
||||||
return app_name.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
|
||||||
const wchar_t* OverlayWindow::get_key()
|
|
||||||
{
|
|
||||||
return app_key.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OverlayWindow::get_config(wchar_t* buffer, int* buffer_size)
|
|
||||||
{
|
|
||||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
|
||||||
|
|
||||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
|
||||||
settings.set_description(GET_RESOURCE_STRING(IDS_SETTINGS_DESCRIPTION));
|
|
||||||
settings.set_overview_link(L"https://aka.ms/PowerToysOverview_ShortcutGuide");
|
|
||||||
settings.set_icon_key(L"pt-shortcut-guide");
|
|
||||||
|
|
||||||
settings.add_int_spinner(
|
|
||||||
pressTime.name,
|
|
||||||
pressTime.resourceId,
|
|
||||||
pressTime.value,
|
|
||||||
100,
|
|
||||||
10000,
|
|
||||||
100);
|
|
||||||
|
|
||||||
settings.add_int_spinner(
|
|
||||||
overlayOpacity.name,
|
|
||||||
overlayOpacity.resourceId,
|
|
||||||
overlayOpacity.value,
|
|
||||||
0,
|
|
||||||
100,
|
|
||||||
1);
|
|
||||||
|
|
||||||
settings.add_choice_group(
|
|
||||||
theme.name,
|
|
||||||
theme.resourceId,
|
|
||||||
theme.value,
|
|
||||||
theme.keys_and_texts);
|
|
||||||
|
|
||||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::set_config(const wchar_t* config)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// save configuration
|
|
||||||
PowerToysSettings::PowerToyValues _values =
|
|
||||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
|
||||||
_values.save_to_settings_file();
|
|
||||||
Trace::SettingsChanged(pressTime.value, overlayOpacity.value, theme.value);
|
|
||||||
|
|
||||||
// apply new settings if powertoy is enabled
|
|
||||||
if (_enabled)
|
|
||||||
{
|
|
||||||
if (const auto press_delay_time = _values.get_int_value(pressTime.name))
|
|
||||||
{
|
|
||||||
pressTime.value = *press_delay_time;
|
|
||||||
if (target_state)
|
|
||||||
{
|
|
||||||
target_state->set_delay(*press_delay_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (const auto overlay_opacity = _values.get_int_value(overlayOpacity.name))
|
|
||||||
{
|
|
||||||
overlayOpacity.value = *overlay_opacity;
|
|
||||||
if (winkey_popup)
|
|
||||||
{
|
|
||||||
winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value) / 100.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (auto val = _values.get_string_value(theme.name))
|
|
||||||
{
|
|
||||||
theme.value = std::move(*val);
|
|
||||||
if (winkey_popup)
|
|
||||||
{
|
|
||||||
winkey_popup->set_theme(theme.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (auto val = _values.get_string_value(disabledApps.name))
|
|
||||||
{
|
|
||||||
disabledApps.value = std::move(*val);
|
|
||||||
update_disabled_apps();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
// Improper JSON. TODO: handle the error.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr int alternative_switch_hotkey_id = 0x2;
|
|
||||||
constexpr UINT alternative_switch_modifier_mask = MOD_WIN | MOD_SHIFT;
|
|
||||||
constexpr UINT alternative_switch_vk_code = VK_OEM_2;
|
|
||||||
|
|
||||||
void OverlayWindow::enable()
|
|
||||||
{
|
|
||||||
Logger::info("Shortcut Guide is enabling");
|
|
||||||
|
|
||||||
auto switcher = [&](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT {
|
|
||||||
if (msg == WM_KEYDOWN && wparam == VK_ESCAPE && instance->target_state->active())
|
|
||||||
{
|
|
||||||
instance->target_state->toggle_force_shown();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg == WM_APP && lparam == eventActivateWindow)
|
|
||||||
{
|
|
||||||
instance->target_state->toggle_force_shown();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg != WM_HOTKEY)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const auto vk_code = HIWORD(lparam);
|
|
||||||
const auto modifiers_mask = LOWORD(lparam);
|
|
||||||
if (alternative_switch_vk_code != vk_code || alternative_switch_modifier_mask != modifiers_mask)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
instance->target_state->toggle_force_shown();
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!_enabled)
|
|
||||||
{
|
|
||||||
Trace::EnableShortcutGuide(true);
|
|
||||||
winkey_popup = std::make_unique<D2DOverlayWindow>(std::move(switcher));
|
|
||||||
winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value) / 100.0f);
|
|
||||||
winkey_popup->set_theme(theme.value);
|
|
||||||
target_state = std::make_unique<TargetState>(pressTime.value);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
winkey_popup->initialize();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
Logger::critical("Winkey popup failed to initialize");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(DISABLE_LOWLEVEL_HOOKS_WHEN_DEBUGGED)
|
|
||||||
const bool hook_disabled = IsDebuggerPresent();
|
|
||||||
#else
|
|
||||||
const bool hook_disabled = false;
|
|
||||||
#endif
|
|
||||||
if (!hook_disabled)
|
|
||||||
{
|
|
||||||
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), NULL);
|
|
||||||
if (!hook_handle)
|
|
||||||
{
|
|
||||||
DWORD errorCode = GetLastError();
|
|
||||||
show_last_error_message(L"SetWindowsHookEx", errorCode, L"PowerToys - Shortcut Guide");
|
|
||||||
auto errorMessage = get_last_error_message(errorCode);
|
|
||||||
Trace::Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"OverlayWindow.enable.SetWindowsHookEx");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RegisterHotKey(winkey_popup->get_window_handle(), alternative_switch_hotkey_id, alternative_switch_modifier_mask, alternative_switch_vk_code);
|
|
||||||
|
|
||||||
auto show_action = [&]() {
|
|
||||||
PostMessageW(winkey_popup->get_window_handle(), WM_APP, 0, eventActivateWindow);
|
|
||||||
};
|
|
||||||
|
|
||||||
event_waiter = std::make_unique<NativeEventWaiter>(CommonSharedConstants::SHOW_SHORTCUT_GUIDE_SHARED_EVENT, show_action);
|
|
||||||
}
|
|
||||||
_enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::disable(bool trace_event)
|
|
||||||
{
|
|
||||||
Logger::info("Shortcut Guide is disabling");
|
|
||||||
|
|
||||||
if (_enabled)
|
|
||||||
{
|
|
||||||
_enabled = false;
|
|
||||||
if (trace_event)
|
|
||||||
{
|
|
||||||
Trace::EnableShortcutGuide(false);
|
|
||||||
}
|
|
||||||
UnregisterHotKey(winkey_popup->get_window_handle(), alternative_switch_hotkey_id);
|
|
||||||
event_waiter.reset();
|
|
||||||
winkey_popup->hide();
|
|
||||||
target_state->exit();
|
|
||||||
target_state.reset();
|
|
||||||
winkey_popup.reset();
|
|
||||||
if (hook_handle)
|
|
||||||
{
|
|
||||||
bool success = UnhookWindowsHookEx(hook_handle);
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
hook_handle = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::disable()
|
|
||||||
{
|
|
||||||
this->disable(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OverlayWindow::is_enabled()
|
|
||||||
{
|
|
||||||
return _enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
intptr_t OverlayWindow::signal_event(LowlevelKeyboardEvent* event)
|
|
||||||
{
|
|
||||||
if (!_enabled)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->wParam == WM_KEYDOWN ||
|
|
||||||
event->wParam == WM_SYSKEYDOWN ||
|
|
||||||
event->wParam == WM_KEYUP ||
|
|
||||||
event->wParam == WM_SYSKEYUP)
|
|
||||||
{
|
|
||||||
bool suppress = target_state->signal_event(event->lParam->vkCode,
|
|
||||||
event->wParam == WM_KEYDOWN || event->wParam == WM_SYSKEYDOWN);
|
|
||||||
return suppress ? 1 : 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::on_held()
|
|
||||||
{
|
|
||||||
auto windowInfo = GetShortcutGuideWindowInfo();
|
|
||||||
if (windowInfo.disabled)
|
|
||||||
{
|
|
||||||
target_state->was_hidden();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
winkey_popup->show(windowInfo.hwnd, windowInfo.snappable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::on_held_press(DWORD vkCode)
|
|
||||||
{
|
|
||||||
winkey_popup->animate(vkCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::quick_hide()
|
|
||||||
{
|
|
||||||
winkey_popup->quick_hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::was_hidden()
|
|
||||||
{
|
|
||||||
target_state->was_hidden();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::destroy()
|
|
||||||
{
|
|
||||||
this->disable(false);
|
|
||||||
delete this;
|
|
||||||
instance = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OverlayWindow::overlay_visible() const
|
|
||||||
{
|
|
||||||
return target_state->active();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::init_settings()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PowerToysSettings::PowerToyValues settings =
|
|
||||||
PowerToysSettings::PowerToyValues::load_from_settings_file(OverlayWindow::get_key());
|
|
||||||
if (const auto val = settings.get_int_value(pressTime.name))
|
|
||||||
{
|
|
||||||
pressTime.value = *val;
|
|
||||||
}
|
|
||||||
if (const auto val = settings.get_int_value(overlayOpacity.name))
|
|
||||||
{
|
|
||||||
overlayOpacity.value = *val;
|
|
||||||
}
|
|
||||||
if (auto val = settings.get_string_value(theme.name))
|
|
||||||
{
|
|
||||||
theme.value = std::move(*val);
|
|
||||||
}
|
|
||||||
if (auto val = settings.get_string_value(disabledApps.name))
|
|
||||||
{
|
|
||||||
disabledApps.value = std::move(*val);
|
|
||||||
update_disabled_apps();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception&)
|
|
||||||
{
|
|
||||||
// Error while loading from the settings file. Just let default values stay as they are.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OverlayWindow::is_disabled_app(wchar_t* exePath)
|
|
||||||
{
|
|
||||||
if (exePath == nullptr)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto exePathUpper = std::wstring(exePath);
|
|
||||||
CharUpperBuffW(exePathUpper.data(), (DWORD)exePathUpper.length());
|
|
||||||
|
|
||||||
for (const auto& row : disabled_apps_array)
|
|
||||||
{
|
|
||||||
const auto pos = exePathUpper.rfind(row);
|
|
||||||
const auto last_slash = exePathUpper.rfind('\\');
|
|
||||||
// Check that row occurs in disabled_apps_array, and its last occurrence contains in itself the first character after the last backslash.
|
|
||||||
if (pos != std::wstring::npos && pos <= last_slash + 1 && pos + row.length() > last_slash)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::update_disabled_apps()
|
|
||||||
{
|
|
||||||
disabled_apps_array.clear();
|
|
||||||
auto disabledUppercase = disabledApps.value;
|
|
||||||
CharUpperBuffW(disabledUppercase.data(), (DWORD)disabledUppercase.length());
|
|
||||||
std::wstring_view view(disabledUppercase);
|
|
||||||
view = trim(view);
|
|
||||||
while (!view.empty())
|
|
||||||
{
|
|
||||||
auto pos = (std::min)(view.find_first_of(L"\r\n"), view.length());
|
|
||||||
disabled_apps_array.emplace_back(view.substr(0, pos));
|
|
||||||
view.remove_prefix(pos);
|
|
||||||
view = trim(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverlayWindow::get_exe_path(HWND window, wchar_t* path)
|
|
||||||
{
|
|
||||||
if (disabled_apps_array.empty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD pid = 0;
|
|
||||||
GetWindowThreadProcessId(window, &pid);
|
|
||||||
if (pid != 0)
|
|
||||||
{
|
|
||||||
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
|
||||||
if (processHandle && GetProcessImageFileName(processHandle, path, MAX_PATH) > 0)
|
|
||||||
{
|
|
||||||
CloseHandle(processHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="pch.cpp" />
|
|
||||||
<ClCompile Include="dllmain.cpp" />
|
|
||||||
<ClCompile Include="keyboard_state.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="shortcut_guide.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="target_state.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="overlay_window.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="trace.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="d2d_svg.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="d2d_text.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="d2d_window.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="animation.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="start_visible.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="tasklist_positions.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="native_event_waiter.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="pch.h" />
|
|
||||||
<ClInclude Include="keyboard_state.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="shortcut_guide.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="target_state.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="overlay_window.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="trace.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Generated Files/resource.h">
|
|
||||||
<Filter>Generated Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="ShortcutGuideConstants.h" />
|
|
||||||
<ClInclude Include="d2d_svg.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="d2d_text.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="d2d_window.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="animation.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="start_visible.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="native_event_waiter.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Filter Include="Header Files">
|
|
||||||
<UniqueIdentifier>{2c7c97f7-0d87-4230-a4b2-baf2cfc35d58}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Source Files">
|
|
||||||
<UniqueIdentifier>{aa4b6713-589d-42ef-804d-3a045833f83f}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Resource Files">
|
|
||||||
<UniqueIdentifier>{d7932c11-20ad-4625-adbc-0780ea5e308d}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Generated Files">
|
|
||||||
<UniqueIdentifier>{41a2f27e-76b5-4799-94c3-90a33a71786b}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="packages.config" />
|
|
||||||
<None Include="Resources.resx">
|
|
||||||
<Filter>Resource Files</Filter>
|
|
||||||
</None>
|
|
||||||
<None Include="shortcut_guide.base.rc">
|
|
||||||
<Filter>Resource Files</Filter>
|
|
||||||
</None>
|
|
||||||
<None Include="resource.base.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ResourceCompile Include="Generated Files/shortcut_guide.rc">
|
|
||||||
<Filter>Generated Files</Filter>
|
|
||||||
</ResourceCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
@ -1,250 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "target_state.h"
|
|
||||||
#include "start_visible.h"
|
|
||||||
#include "keyboard_state.h"
|
|
||||||
#include <common/interop/shared_constants.h>
|
|
||||||
#include <common/logger/logger.h>
|
|
||||||
|
|
||||||
TargetState::TargetState(int ms_delay) :
|
|
||||||
// TODO: All this processing should be done w/o a separate thread etc. in pre_wnd_proc of winkey_popup to avoid
|
|
||||||
// multithreading. Use SetTimer for delayed events
|
|
||||||
delay(std::chrono::milliseconds(ms_delay)),
|
|
||||||
thread(&TargetState::thread_proc, this)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr unsigned VK_S = 0x53;
|
|
||||||
|
|
||||||
bool TargetState::signal_event(unsigned vk_code, bool key_down)
|
|
||||||
{
|
|
||||||
std::unique_lock lock(mutex);
|
|
||||||
// Ignore repeated key presses
|
|
||||||
if (!events.empty() && events.back().key_down == key_down && events.back().vk_code == vk_code)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Hide the overlay when WinKey + Shift + S is pressed
|
|
||||||
if (key_down && state == Shown && vk_code == VK_S && (GetKeyState(VK_LSHIFT) || GetKeyState(VK_RSHIFT)))
|
|
||||||
{
|
|
||||||
// We cannot use normal hide() here, there is stuff that needs deinitialization.
|
|
||||||
// It can be safely done when the user releases the WinKey.
|
|
||||||
instance->quick_hide();
|
|
||||||
}
|
|
||||||
const bool win_key_released = !key_down && (vk_code == VK_LWIN || vk_code == VK_RWIN);
|
|
||||||
constexpr auto overlay_fade_in_animation_time = std::chrono::milliseconds(300);
|
|
||||||
const auto overlay_active = state == Shown && (std::chrono::system_clock::now() - signal_timestamp > overlay_fade_in_animation_time);
|
|
||||||
const bool suppress_win_release = win_key_released && (state == ForceShown || overlay_active) && !nonwin_key_was_pressed_during_shown;
|
|
||||||
|
|
||||||
events.push_back({ key_down, vk_code });
|
|
||||||
lock.unlock();
|
|
||||||
cv.notify_one();
|
|
||||||
if (suppress_win_release)
|
|
||||||
{
|
|
||||||
// Send a 0xFF VK code, which is outside of the VK code range, to prevent
|
|
||||||
// the start menu from appearing.
|
|
||||||
INPUT input[3] = { {}, {}, {} };
|
|
||||||
input[0].type = INPUT_KEYBOARD;
|
|
||||||
input[0].ki.wVk = 0xFF;
|
|
||||||
input[0].ki.dwExtraInfo = CommonSharedConstants::KEYBOARDMANAGER_INJECTED_FLAG;
|
|
||||||
input[1].type = INPUT_KEYBOARD;
|
|
||||||
input[1].ki.wVk = 0xFF;
|
|
||||||
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
input[1].ki.dwExtraInfo = CommonSharedConstants::KEYBOARDMANAGER_INJECTED_FLAG;
|
|
||||||
input[2].type = INPUT_KEYBOARD;
|
|
||||||
input[2].ki.wVk = vk_code;
|
|
||||||
input[2].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
||||||
input[2].ki.dwExtraInfo = CommonSharedConstants::KEYBOARDMANAGER_INJECTED_FLAG;
|
|
||||||
SendInput(3, input, sizeof(INPUT));
|
|
||||||
}
|
|
||||||
return suppress_win_release;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TargetState::was_hidden()
|
|
||||||
{
|
|
||||||
std::unique_lock<std::recursive_mutex> lock(mutex);
|
|
||||||
// Ignore callbacks from the D2DOverlayWindow
|
|
||||||
if (state == ForceShown)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state = Hidden;
|
|
||||||
events.clear();
|
|
||||||
lock.unlock();
|
|
||||||
cv.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TargetState::exit()
|
|
||||||
{
|
|
||||||
std::unique_lock lock(mutex);
|
|
||||||
events.clear();
|
|
||||||
state = Exiting;
|
|
||||||
lock.unlock();
|
|
||||||
cv.notify_one();
|
|
||||||
thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyEvent TargetState::next()
|
|
||||||
{
|
|
||||||
auto e = events.front();
|
|
||||||
events.pop_front();
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TargetState::handle_hidden()
|
|
||||||
{
|
|
||||||
std::unique_lock lock(mutex);
|
|
||||||
if (events.empty())
|
|
||||||
cv.wait(lock);
|
|
||||||
if (events.empty() || state == Exiting)
|
|
||||||
return;
|
|
||||||
auto event = next();
|
|
||||||
if (event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN))
|
|
||||||
{
|
|
||||||
state = Timeout;
|
|
||||||
winkey_timestamp = std::chrono::system_clock::now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TargetState::handle_shown(const bool forced)
|
|
||||||
{
|
|
||||||
std::unique_lock lock(mutex);
|
|
||||||
if (events.empty())
|
|
||||||
{
|
|
||||||
cv.wait(lock);
|
|
||||||
}
|
|
||||||
if (events.empty() || state == Exiting)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto event = next();
|
|
||||||
if (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN)
|
|
||||||
{
|
|
||||||
if (!forced && (!event.key_down || !winkey_held()))
|
|
||||||
{
|
|
||||||
state = Hidden;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key_down)
|
|
||||||
{
|
|
||||||
nonwin_key_was_pressed_during_shown = true;
|
|
||||||
lock.unlock();
|
|
||||||
instance->on_held_press(event.vk_code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TargetState::thread_proc()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case Hidden:
|
|
||||||
handle_hidden();
|
|
||||||
break;
|
|
||||||
case Timeout:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
handle_timeout();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
Logger::critical("Timeout, handle_timeout failed.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Shown:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
handle_shown(false);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
Logger::critical("Shown, handle_shown failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case ForceShown:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
handle_shown(true);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
Logger::critical("ForceShown, handle_shown failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case Exiting:
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TargetState::handle_timeout()
|
|
||||||
{
|
|
||||||
std::unique_lock lock(mutex);
|
|
||||||
auto wait_time = delay - (std::chrono::system_clock::now() - winkey_timestamp);
|
|
||||||
if (events.empty())
|
|
||||||
{
|
|
||||||
cv.wait_for(lock, wait_time);
|
|
||||||
}
|
|
||||||
if (state == Exiting)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip all VK_*WIN-down events
|
|
||||||
while (!events.empty())
|
|
||||||
{
|
|
||||||
auto event = events.front();
|
|
||||||
if (event.key_down && (event.vk_code == VK_LWIN || event.vk_code == VK_RWIN))
|
|
||||||
events.pop_front();
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// If we've detected that a user is holding anything other than VK_*WIN or start menu is visible, we should hide
|
|
||||||
if (!events.empty() || !only_winkey_key_held() || is_start_visible())
|
|
||||||
{
|
|
||||||
state = Hidden;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std::chrono::system_clock::now() - winkey_timestamp < delay)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
signal_timestamp = std::chrono::system_clock::now();
|
|
||||||
nonwin_key_was_pressed_during_shown = false;
|
|
||||||
state = Shown;
|
|
||||||
lock.unlock();
|
|
||||||
instance->on_held();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TargetState::set_delay(int ms_delay)
|
|
||||||
{
|
|
||||||
std::unique_lock lock(mutex);
|
|
||||||
delay = std::chrono::milliseconds(ms_delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TargetState::toggle_force_shown()
|
|
||||||
{
|
|
||||||
std::unique_lock lock(mutex);
|
|
||||||
events.clear();
|
|
||||||
if (state != ForceShown)
|
|
||||||
{
|
|
||||||
state = ForceShown;
|
|
||||||
instance->on_held();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state = Hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TargetState::active() const
|
|
||||||
{
|
|
||||||
return state == ForceShown || state == Shown;
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <deque>
|
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <chrono>
|
|
||||||
#include "shortcut_guide.h"
|
|
||||||
|
|
||||||
struct KeyEvent
|
|
||||||
{
|
|
||||||
bool key_down;
|
|
||||||
unsigned vk_code;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TargetState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TargetState(int ms_delay);
|
|
||||||
bool signal_event(unsigned vk_code, bool key_down);
|
|
||||||
void was_hidden();
|
|
||||||
void exit();
|
|
||||||
void set_delay(int ms_delay);
|
|
||||||
|
|
||||||
void toggle_force_shown();
|
|
||||||
bool active() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
KeyEvent next();
|
|
||||||
void handle_hidden();
|
|
||||||
void handle_timeout();
|
|
||||||
void handle_shown(const bool forced);
|
|
||||||
void thread_proc();
|
|
||||||
std::recursive_mutex mutex;
|
|
||||||
std::condition_variable_any cv;
|
|
||||||
std::chrono::system_clock::time_point winkey_timestamp, signal_timestamp;
|
|
||||||
std::chrono::milliseconds delay;
|
|
||||||
std::deque<KeyEvent> events;
|
|
||||||
enum State
|
|
||||||
{
|
|
||||||
Hidden,
|
|
||||||
Timeout,
|
|
||||||
Shown,
|
|
||||||
ForceShown,
|
|
||||||
Exiting
|
|
||||||
};
|
|
||||||
std::atomic<State> state = Hidden;
|
|
||||||
|
|
||||||
bool nonwin_key_was_pressed_during_shown = false;
|
|
||||||
std::thread thread;
|
|
||||||
};
|
|
@ -1,80 +0,0 @@
|
|||||||
#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() noexcept
|
|
||||||
{
|
|
||||||
TraceLoggingRegister(g_hProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Trace::UnregisterProvider() noexcept
|
|
||||||
{
|
|
||||||
TraceLoggingUnregister(g_hProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Trace::HideGuide(const __int64 duration_ms, std::vector<int>& key_pressed) noexcept
|
|
||||||
{
|
|
||||||
std::string vk_codes;
|
|
||||||
std::vector<int>::iterator it;
|
|
||||||
for (it = key_pressed.begin(); it != key_pressed.end();)
|
|
||||||
{
|
|
||||||
vk_codes += std::to_string(*it);
|
|
||||||
if (++it != key_pressed.end())
|
|
||||||
{
|
|
||||||
vk_codes += " ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TraceLoggingWrite(
|
|
||||||
g_hProvider,
|
|
||||||
"ShortcutGuide_HideGuide",
|
|
||||||
TraceLoggingInt64(duration_ms, "DurationInMs"),
|
|
||||||
TraceLoggingInt64(key_pressed.size(), "NumberOfKeysPressed"),
|
|
||||||
TraceLoggingString(vk_codes.c_str(), "ListOfKeysPressed"),
|
|
||||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
|
||||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
|
||||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Trace::EnableShortcutGuide(const bool enabled) noexcept
|
|
||||||
{
|
|
||||||
TraceLoggingWrite(
|
|
||||||
g_hProvider,
|
|
||||||
"ShortcutGuide_EnableGuide",
|
|
||||||
TraceLoggingBoolean(enabled, "Enabled"),
|
|
||||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
|
||||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
|
||||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Trace::SettingsChanged(const int press_delay_time, const int overlay_opacity, const std::wstring& theme) noexcept
|
|
||||||
{
|
|
||||||
TraceLoggingWrite(
|
|
||||||
g_hProvider,
|
|
||||||
"ShortcutGuide_SettingsChanged",
|
|
||||||
TraceLoggingInt32(press_delay_time, "PressDelayTime"),
|
|
||||||
TraceLoggingInt32(overlay_opacity, "OverlayOpacity"),
|
|
||||||
TraceLoggingWideString(theme.c_str(), "Theme"),
|
|
||||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
|
||||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
|
||||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log if an error occurs in Shortcut Guide
|
|
||||||
void Trace::Error(const DWORD errorCode, std::wstring errorMessage, std::wstring methodName) noexcept
|
|
||||||
{
|
|
||||||
TraceLoggingWrite(
|
|
||||||
g_hProvider,
|
|
||||||
"ShortcutGuide_Error",
|
|
||||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
|
||||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
|
||||||
TraceLoggingValue(methodName.c_str(), "MethodName"),
|
|
||||||
TraceLoggingValue(errorCode, "ErrorCode"),
|
|
||||||
TraceLoggingValue(errorMessage.c_str(), "ErrorMessage"));
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class Trace
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void RegisterProvider() noexcept;
|
|
||||||
static void UnregisterProvider() noexcept;
|
|
||||||
static void HideGuide(const __int64 duration_ms, std::vector<int>& key_pressed) noexcept;
|
|
||||||
static void EnableShortcutGuide(const bool enabled) noexcept;
|
|
||||||
static void SettingsChanged(const int press_delay_time, const int overlay_opacity, const std::wstring& theme) noexcept;
|
|
||||||
static void Error(const DWORD errorCode, std::wstring errorMessage, std::wstring methodName) noexcept;
|
|
||||||
};
|
|
121
src/runner/CentralizedHotkeys.cpp
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "CentralizedHotkeys.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <common/logger/logger.h>
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
|
|
||||||
|
namespace CentralizedHotkeys
|
||||||
|
{
|
||||||
|
std::map<Shortcut, std::vector<Action>> actions;
|
||||||
|
std::map<Shortcut, int> ids;
|
||||||
|
HWND runnerWindow;
|
||||||
|
|
||||||
|
std::wstring ToWstring(const Shortcut& shortcut)
|
||||||
|
{
|
||||||
|
std::wstring res = L"";
|
||||||
|
if (shortcut.modifiersMask & MOD_SHIFT)
|
||||||
|
{
|
||||||
|
res += L"shift+";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcut.modifiersMask & MOD_CONTROL)
|
||||||
|
{
|
||||||
|
res += L"ctrl+";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcut.modifiersMask & MOD_WIN)
|
||||||
|
{
|
||||||
|
res += L"win+";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcut.modifiersMask & MOD_ALT)
|
||||||
|
{
|
||||||
|
res += L"alt+";
|
||||||
|
}
|
||||||
|
|
||||||
|
res += PowerToysSettings::HotkeyObject::key_from_code(shortcut.vkCode);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddHotkeyAction(Shortcut shortcut, Action action)
|
||||||
|
{
|
||||||
|
if (!actions[shortcut].empty())
|
||||||
|
{
|
||||||
|
// It will only work if previous one is rewritten
|
||||||
|
Logger::warn(L"{} shortcut is already registered", ToWstring(shortcut));
|
||||||
|
}
|
||||||
|
|
||||||
|
actions[shortcut].push_back(action);
|
||||||
|
// Register hotkey if it is the first shortcut
|
||||||
|
if (actions[shortcut].size() == 1)
|
||||||
|
{
|
||||||
|
if (ids.find(shortcut) == ids.end())
|
||||||
|
{
|
||||||
|
static int nextId = 0;
|
||||||
|
ids[shortcut] = nextId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RegisterHotKey(runnerWindow, ids[shortcut], shortcut.modifiersMask, shortcut.vkCode))
|
||||||
|
{
|
||||||
|
Logger::warn(L"Failed to add {} shortcut. {}", ToWstring(shortcut), get_last_error_or_default(GetLastError()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::trace(L"{} shortcut registered", ToWstring(shortcut));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnregisterHotkeysForModule(std::wstring moduleName)
|
||||||
|
{
|
||||||
|
for (auto it = actions.begin(); it != actions.end(); it++)
|
||||||
|
{
|
||||||
|
auto val = std::find_if(it->second.begin(), it->second.end(), [moduleName](Action a) { return a.moduleName == moduleName; });
|
||||||
|
if (val != it->second.end())
|
||||||
|
{
|
||||||
|
it->second.erase(val);
|
||||||
|
|
||||||
|
if (it->second.empty())
|
||||||
|
{
|
||||||
|
if (!UnregisterHotKey(runnerWindow, ids[it->first]))
|
||||||
|
{
|
||||||
|
Logger::warn(L"Failed to unregister {} shortcut. {}", ToWstring(it->first), get_last_error_or_default(GetLastError()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::trace(L"{} shortcut unregistered", ToWstring(it->first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopulateHotkey(Shortcut shortcut)
|
||||||
|
{
|
||||||
|
if (!actions.empty())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
actions[shortcut].begin()->action(shortcut.modifiersMask, shortcut.vkCode);
|
||||||
|
}
|
||||||
|
catch(std::exception ex)
|
||||||
|
{
|
||||||
|
Logger::error("Failed to execute hotkey's action. {}", ex.what());
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to execute hotkey's action");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterWindow(HWND hwnd)
|
||||||
|
{
|
||||||
|
runnerWindow = hwnd;
|
||||||
|
}
|
||||||
|
}
|
45
src/runner/CentralizedHotkeys.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace CentralizedHotkeys
|
||||||
|
{
|
||||||
|
struct Action
|
||||||
|
{
|
||||||
|
std::wstring moduleName;
|
||||||
|
std::function<void(WORD, WORD)> action;
|
||||||
|
|
||||||
|
Action(std::wstring moduleName = L"", std::function<void(WORD, WORD)> action = ([](WORD modifiersMask, WORD vkCode) {}))
|
||||||
|
{
|
||||||
|
this->moduleName = moduleName;
|
||||||
|
this->action = action;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Shortcut
|
||||||
|
{
|
||||||
|
WORD modifiersMask;
|
||||||
|
WORD vkCode;
|
||||||
|
|
||||||
|
Shortcut(WORD modifiersMask = 0, WORD vkCode = 0)
|
||||||
|
{
|
||||||
|
this->modifiersMask = modifiersMask;
|
||||||
|
this->vkCode = vkCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const Shortcut& key) const
|
||||||
|
{
|
||||||
|
return std::pair<WORD, WORD>{ this->modifiersMask, this->vkCode } < std::pair<WORD, WORD>{ key.modifiersMask, key.vkCode };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::wstring ToWstring(const Shortcut& shortcut);
|
||||||
|
|
||||||
|
bool AddHotkeyAction(Shortcut shortcut, Action action);
|
||||||
|
|
||||||
|
void UnregisterHotkeysForModule(std::wstring moduleName);
|
||||||
|
|
||||||
|
void PopulateHotkey(Shortcut shortcut);
|
||||||
|
|
||||||
|
void RegisterWindow(HWND hwnd);
|
||||||
|
}
|
@ -32,6 +32,7 @@
|
|||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
#include <RestartManager.h>
|
#include <RestartManager.h>
|
||||||
#include "centralized_kb_hook.h"
|
#include "centralized_kb_hook.h"
|
||||||
|
#include "CentralizedHotkeys.h"
|
||||||
|
|
||||||
#if _DEBUG && _WIN64
|
#if _DEBUG && _WIN64
|
||||||
#include "unhandled_exception_handler.h"
|
#include "unhandled_exception_handler.h"
|
||||||
@ -155,7 +156,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
|
|||||||
L"modules/KeyboardManager/KeyboardManager.dll",
|
L"modules/KeyboardManager/KeyboardManager.dll",
|
||||||
L"modules/Launcher/Microsoft.Launcher.dll",
|
L"modules/Launcher/Microsoft.Launcher.dll",
|
||||||
L"modules/PowerRename/PowerRenameExt.dll",
|
L"modules/PowerRename/PowerRenameExt.dll",
|
||||||
L"modules/ShortcutGuide/ShortcutGuide.dll",
|
L"modules/ShortcutGuide/ShortcutGuideModuleInterface/ShortcutGuideModuleInterface.dll",
|
||||||
L"modules/ColorPicker/ColorPicker.dll",
|
L"modules/ColorPicker/ColorPicker.dll",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "powertoy_module.h"
|
#include "powertoy_module.h"
|
||||||
#include "centralized_kb_hook.h"
|
#include "centralized_kb_hook.h"
|
||||||
|
#include "CentralizedHotkeys.h"
|
||||||
#include <common/logger/logger.h>
|
#include <common/logger/logger.h>
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
|
|
||||||
std::map<std::wstring, PowertoyModule>& modules()
|
std::map<std::wstring, PowertoyModule>& modules()
|
||||||
{
|
{
|
||||||
@ -46,6 +48,7 @@ PowertoyModule::PowertoyModule(PowertoyModuleIface* pt_module, HMODULE handle) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_hotkeys();
|
update_hotkeys();
|
||||||
|
UpdateHotkeyEx();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowertoyModule::update_hotkeys()
|
void PowertoyModule::update_hotkeys()
|
||||||
@ -66,3 +69,19 @@ void PowertoyModule::update_hotkeys()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PowertoyModule::UpdateHotkeyEx()
|
||||||
|
{
|
||||||
|
CentralizedHotkeys::UnregisterHotkeysForModule(pt_module->get_key());
|
||||||
|
auto container = pt_module->GetHotkeyEx();
|
||||||
|
if (container.has_value())
|
||||||
|
{
|
||||||
|
auto hotkey = container.value();
|
||||||
|
auto modulePtr = pt_module.get();
|
||||||
|
auto action = [modulePtr](WORD modifiersMask, WORD vkCode) {
|
||||||
|
modulePtr->OnHotkeyEx();
|
||||||
|
};
|
||||||
|
|
||||||
|
CentralizedHotkeys::AddHotkeyAction({ hotkey.modifiersMask, hotkey.vkCode }, { pt_module->get_key(), action });
|
||||||
|
}
|
||||||
|
}
|
||||||
|