Mouse Utils - Find My Mouse (#13916)
* Initial FindMyMouse implementation * Proper enable/disable code * Settings page * Change FindMyMouse window name * Add Oobe page. * Add icons * Change settings preview * Fix mouse utilities aka.ms link spelling * Remove right control exit behavior * Remove dllmain boilerplate comments and code * Add filters to vcxproj * Add logging * Add telemetry * Add installer instructions * Add dll to pipelines * Fix Task Manager name for runner changing * Add a description in dllmain * Proper resource file creation * Add reference of link to the docs * Fix spellchecker errors * Call DestroyWindow on correct thread * Add attribution * Proper ordering of module in Settings and Oobe * Update Target Platform Version to 18362 * Fix project filters * Add attribution to Community.md * Lowercase "utilities" * [Mouse utils] Adding icon (#13933) * Adding images to docs folder * Updated imagery Co-authored-by: Laute <Niels.Laute@philips.com> * Add settings deeplink Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: Laute <Niels.Laute@philips.com>
17
.github/actions/spell-check/expect.txt
vendored
@ -5,6 +5,7 @@ abcdef
|
||||
abcdefgh
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
abgr
|
||||
abi
|
||||
ABlocked
|
||||
Abug
|
||||
accctrl
|
||||
@ -382,6 +383,7 @@ CXVIRTUALSCREEN
|
||||
cxx
|
||||
cxxopts
|
||||
CYSMICON
|
||||
CYVIRTUALSCREEN
|
||||
cziplib
|
||||
Dac
|
||||
dacl
|
||||
@ -493,6 +495,8 @@ DPICHANGED
|
||||
DPolicy
|
||||
DPopup
|
||||
DPSAPI
|
||||
DQTAT
|
||||
DQTYPE
|
||||
DRAWFRAME
|
||||
drawingcolor
|
||||
dreamsofameaningfullife
|
||||
@ -788,6 +792,7 @@ hotspot
|
||||
HPAINTBUFFER
|
||||
hpj
|
||||
hpp
|
||||
HRAWINPUT
|
||||
hread
|
||||
HREDRAW
|
||||
href
|
||||
@ -807,6 +812,7 @@ Htmdid
|
||||
html
|
||||
htt
|
||||
http
|
||||
HTTRANSPARENT
|
||||
hwb
|
||||
HWINEVENTHOOK
|
||||
hwnd
|
||||
@ -840,6 +846,7 @@ ICollection
|
||||
IColor
|
||||
ICommand
|
||||
IComparer
|
||||
ICompositor
|
||||
ICONERROR
|
||||
ICONINFORMATION
|
||||
IContext
|
||||
@ -854,6 +861,7 @@ IDesktop
|
||||
IDictionary
|
||||
IDirectory
|
||||
IDispatch
|
||||
IDispatcher
|
||||
IDisposable
|
||||
idl
|
||||
IDLIST
|
||||
@ -941,6 +949,7 @@ INPUTHARDWARE
|
||||
INPUTKEYBOARD
|
||||
INPUTLANGCHANGED
|
||||
INPUTMOUSE
|
||||
INPUTSINK
|
||||
INPUTTYPE
|
||||
INSTALLDESKTOPSHORTCUT
|
||||
INSTALLDIR
|
||||
@ -1702,6 +1711,9 @@ Radiobuttons
|
||||
RAII
|
||||
RAlt
|
||||
randyrants
|
||||
RAWINPUT
|
||||
RAWINPUTDEVICE
|
||||
RAWINPUTHEADER
|
||||
RAWPATH
|
||||
rbegin
|
||||
Rbp
|
||||
@ -1786,6 +1798,7 @@ rgs
|
||||
rhs
|
||||
ricardosantos
|
||||
Richtext
|
||||
RIDEV
|
||||
RIGHTSCROLLBAR
|
||||
riid
|
||||
riverar
|
||||
@ -2165,7 +2178,9 @@ tsx
|
||||
TYMED
|
||||
typedef
|
||||
TYPEKEY
|
||||
TYPEKEYBOARD
|
||||
TYPELIB
|
||||
TYPEMOUSE
|
||||
typename
|
||||
typeof
|
||||
typeparam
|
||||
@ -2468,6 +2483,7 @@ XSmall
|
||||
XStr
|
||||
XToolset
|
||||
xunit
|
||||
XVIRTUALSCREEN
|
||||
Yaml
|
||||
YDiff
|
||||
YIncrement
|
||||
@ -2478,6 +2494,7 @@ YStr
|
||||
YUY
|
||||
yuyoyuppe
|
||||
YUYV
|
||||
YVIRTUALSCREEN
|
||||
YVU
|
||||
YVYU
|
||||
ZEROINIT
|
||||
|
@ -170,6 +170,7 @@ build:
|
||||
- 'modules\launcher\Wox.dll'
|
||||
- 'modules\launcher\Wox.Infrastructure.dll'
|
||||
- 'modules\launcher\Wox.Plugin.dll'
|
||||
- 'modules\MouseUtils\FindMyMouse.dll'
|
||||
- 'modules\PowerRename\PowerRenameExt.dll'
|
||||
- 'modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe'
|
||||
- 'modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.dll'
|
||||
|
@ -72,6 +72,10 @@ PowerToys Awake is a tool to keep your computer awake.
|
||||
|
||||
Color Picker is from Martin.
|
||||
|
||||
### [@oldnewthing](https://github.com/oldnewthing) - Raymond Chen
|
||||
|
||||
Find My Mouse is based on Raymond Chen's SuperSonar.
|
||||
|
||||
### Microsoft InVEST team
|
||||
|
||||
This amazing team helped PowerToys develop PowerToys Run and Keyboard manager as well as update our Settings to v2. @alekhyareddy28, @arjunbalgovind, @jyuwono @laviusmotileng-ms, @ryanbodrug-microsoft, @saahmedm, @somil55, @traies, @udit3333
|
||||
|
@ -372,6 +372,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plu
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests.csproj", "{4ED320BC-BA04-4D42-8D15-CBE62151F08B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MouseUtils", "MouseUtils", "{322566EF-20DC-43A6-B9F8-616AF942579A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FindMyMouse", "src\modules\MouseUtils\FindMyMouse\FindMyMouse.vcxproj", "{E94FD11C-0591-456F-899F-EFC0CA548336}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@ -981,6 +985,12 @@ Global
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x64.Build.0 = Release|x64
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Debug|x64.Build.0 = Debug|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Release|x64.ActiveCfg = Release|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Release|x64.Build.0 = Release|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Release|x86.ActiveCfg = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -1098,6 +1108,8 @@ Global
|
||||
{F40C3397-1834-4530-B2D9-8F8B8456BCDF} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{322566EF-20DC-43A6-B9F8-616AF942579A} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
@ -19,7 +19,7 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
| [Awake](https://aka.ms/PowerToysOverview_Awake) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
|
||||
| [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) |
|
||||
| [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
|
||||
| [Video Conference Mute (Experimental)](https://aka.ms/PowerToysOverview_VideoConference) | | |
|
||||
| [Video Conference Mute (Experimental)](https://aka.ms/PowerToysOverview_VideoConference) | [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | |
|
||||
|
||||
## Installing and running Microsoft PowerToys
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
| PowerToysOverview_FileExplorerAddOns | https://docs.microsoft.com/windows/powertoys/file-explorer |
|
||||
| PowerToysOverview_ImageResizer | https://docs.microsoft.com/windows/powertoys/image-resizer |
|
||||
| PowerToysOverview_KeyboardManager | https://docs.microsoft.com/windows/powertoys/keyboard-manager |
|
||||
| PowerToysOverview_MouseUtilities | https://docs.microsoft.com/windows/powertoys/mouse-utilities |
|
||||
| PowerToysOverview_PowerRename | https://docs.microsoft.com/windows/powertoys/powerrename |
|
||||
| PowerToysOverview_PowerToysRun | https://docs.microsoft.com/windows/powertoys/run |
|
||||
| PowerToysOverview_ShortcutGuide | https://docs.microsoft.com/windows/powertoys/shortcut-guide |
|
||||
|
BIN
doc/images/icons/MouseUtils.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
doc/images/overview/MouseUtils_large.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
doc/images/overview/MouseUtils_small.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
doc/images/overview/Original/MouseUtils.png
Normal file
After Width: | Height: | Size: 114 KiB |
@ -10,6 +10,7 @@
|
||||
<?define ColorPickerProjectName="ColorPicker"?>
|
||||
<?define VideoConferenceProjectName="VideoConference"?>
|
||||
<?define AwakeProjectName="Awake"?>
|
||||
<?define MouseUtilsProjectName="MouseUtils"?>
|
||||
|
||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||
<?define BinX32Dir="$(var.RepoDir)x86\$(var.Configuration)\" ?>
|
||||
@ -270,6 +271,10 @@
|
||||
<Directory Id="ColorPickerResourcesFolder" Name="Resources"/>
|
||||
</Directory>
|
||||
|
||||
<!-- Mouse Utils -->
|
||||
<Directory Id="MouseUtilsInstallFolder" Name="$(var.MouseUtilsProjectName)">
|
||||
</Directory>
|
||||
|
||||
<!-- Launcher -->
|
||||
<Directory Id="LauncherInstallFolder" Name="launcher">
|
||||
<Directory Id="AssetsFolder" Name="Assets" />
|
||||
@ -702,6 +707,13 @@
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- MouseUtils -->
|
||||
<DirectoryRef Id="MouseUtilsInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)">
|
||||
<Component Id="Module_FindMyMouse" Guid="60D0E4AE-188F-4403-BF06-1465AACC1BC5" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)\FindMyMouse.dll" KeyPath="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Shortcut guide -->
|
||||
<DirectoryRef Id="ShortcutGuideModuleInterfaceInstallFolder" FileSource="$(var.ShortcutGuideModuleInterface)">
|
||||
<Component Id="Module_ShortcutGuideModuleInterface" Guid="CBD0AC09-91D3-428E-B2B3-05745ADF3473" Win64="yes">
|
||||
@ -903,21 +915,21 @@
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2AssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules">
|
||||
<Component Id="SettingsV2AssetsModules" Guid="A0B961A9-77D0-4223-88A9-E3B41BD9C329" Win64="yes">
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<File Id="SettingsV2AssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2OOBEAssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules\OOBE">
|
||||
<Component Id="SettingsV2OOBEAssetsModules" Guid="E2360A83-6694-4B33-B5F6-641A906359EE" Win64="yes">
|
||||
<?foreach File in ColorPicker.gif;Awake.png;FancyZones.gif;FileExplorer.png;ImageResizer.gif;KBM.gif;PowerRename.gif;Run.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
|
||||
<?foreach File in ColorPicker.gif;Awake.png;FancyZones.gif;FileExplorer.png;ImageResizer.gif;KBM.gif;MouseUtils.gif;PowerRename.gif;Run.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
|
||||
<File Id="SettingsV2OOBEAssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\OOBE\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\FluentIcons">
|
||||
<Component Id="SettingsV2OOBEAssetsFluentIcons" Guid="6A380D5A-DA63-45B5-B68F-06D57CDD1B9C" Win64="yes">
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;FileExplorerPreview.png;ImageResizer.png;KeyboardManager.png;PowerRename.png;PowerToys.png;PowerToysRun.png;Settings.png;ShortcutGuide.png;VideoConferenceMute.png ?>
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;FileExplorerPreview.png;ImageResizer.png;KeyboardManager.png;MouseUtils.png;PowerRename.png;PowerToys.png;PowerToysRun.png;Settings.png;ShortcutGuide.png;VideoConferenceMute.png ?>
|
||||
<File Id="SettingsV2OOBEAssetsFluentIcons_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\FluentIcons\FluentIcons$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
@ -1012,6 +1024,7 @@
|
||||
<ComponentRef Id="Module_Awake_runtime_netstandard20"/>
|
||||
<ComponentRef Id="Module_Awake_runtime_netcoreapp30"/>
|
||||
<ComponentRef Id="Module_Awake_runtime_netcoreapp21"/>
|
||||
<ComponentRef Id="Module_FindMyMouse"/>
|
||||
<ComponentRef Id="SettingsV2" />
|
||||
<ComponentRef Id="SettingsV2Assets" />
|
||||
<ComponentRef Id="SettingsV2AssetsModules" />
|
||||
|
@ -19,6 +19,7 @@ namespace Microsoft.PowerToys.Common.UI
|
||||
Run,
|
||||
ImageResizer,
|
||||
KBM,
|
||||
MouseUtils,
|
||||
PowerRename,
|
||||
FileExplorer,
|
||||
ShortcutGuide,
|
||||
@ -43,6 +44,8 @@ namespace Microsoft.PowerToys.Common.UI
|
||||
return "ImageResizer";
|
||||
case SettingsWindow.KBM:
|
||||
return "KBM";
|
||||
case SettingsWindow.MouseUtils:
|
||||
return "MouseUtils";
|
||||
case SettingsWindow.PowerRename:
|
||||
return "PowerRename";
|
||||
case SettingsWindow.FileExplorer:
|
||||
|
@ -23,6 +23,7 @@ struct LogSettings
|
||||
inline const static std::wstring shortcutGuideLogPath = L"ShortcutGuideLogs\\shortcut-guide-log.txt";
|
||||
inline const static std::string keyboardManagerLoggerName = "keyboard-manager";
|
||||
inline const static std::wstring keyboardManagerLogPath = L"Logs\\keyboard-manager-log.txt";
|
||||
inline const static std::string findMyMouseLoggerName = "find-my-mouse";
|
||||
inline const static int retention = 30;
|
||||
std::wstring logLevel;
|
||||
LogSettings();
|
||||
|
@ -0,0 +1,5 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
|
||||
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 .\ resource.base.h resource.h FindMyMouse.base.rc FindMyMouse.rc" />
|
||||
</Target>
|
||||
</Project>
|
40
src/modules/MouseUtils/FindMyMouse/FindMyMouse.base.rc
Normal file
@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 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" // US English (0x0409), Unicode (0x04B0) charset
|
||||
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 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
814
src/modules/MouseUtils/FindMyMouse/FindMyMouse.cpp
Normal file
@ -0,0 +1,814 @@
|
||||
// FindMyMouse.cpp : Based on Raymond Chen's SuperSonar.cpp
|
||||
//
|
||||
#include "pch.h"
|
||||
#include "FindMyMouse.h"
|
||||
#include "trace.h"
|
||||
|
||||
#ifdef COMPOSITION
|
||||
namespace winrt
|
||||
{
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Composition;
|
||||
}
|
||||
|
||||
namespace ABI
|
||||
{
|
||||
using namespace ABI::Windows::System;
|
||||
using namespace ABI::Windows::UI::Composition::Desktop;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma region Super_Sonar_Base_Code
|
||||
|
||||
template<typename D>
|
||||
struct SuperSonar
|
||||
{
|
||||
bool Initialize(HINSTANCE hinst);
|
||||
void Terminate();
|
||||
|
||||
protected:
|
||||
// You are expected to override these, as appropriate.
|
||||
|
||||
DWORD GetExtendedStyle()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
return BaseWndProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
void BeforeMoveSonar() {}
|
||||
void AfterMoveSonar() {}
|
||||
void SetSonarVisibility(bool visible) = delete;
|
||||
|
||||
protected:
|
||||
// Base class members you can access.
|
||||
D* Shim() { return static_cast<D*>(this); }
|
||||
LRESULT BaseWndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
|
||||
HWND m_hwnd;
|
||||
POINT m_sonarPos = ptNowhere;
|
||||
|
||||
static constexpr int SonarRadius = 100;
|
||||
static constexpr int SonarZoomFactor = 9;
|
||||
static constexpr DWORD FadeDuration = 500;
|
||||
static constexpr int FinalAlphaNumerator = 1;
|
||||
static constexpr int FinalAlphaDenominator = 2;
|
||||
winrt::DispatcherQueueController m_dispatcherQueueController{ nullptr };
|
||||
|
||||
private:
|
||||
static bool IsEqual(POINT const& p1, POINT const& p2)
|
||||
{
|
||||
return p1.x == p2.x && p1.y == p2.y;
|
||||
}
|
||||
|
||||
static constexpr POINT ptNowhere = { -1, -1 };
|
||||
|
||||
static constexpr DWORD TIMER_ID_TRACK = 100;
|
||||
static constexpr DWORD IdlePeriod = 1000;
|
||||
|
||||
// Activate sonar: Hit LeftControl twice.
|
||||
enum class SonarState
|
||||
{
|
||||
Idle,
|
||||
ControlDown1,
|
||||
ControlUp1,
|
||||
ControlDown2,
|
||||
ControlUp2,
|
||||
};
|
||||
|
||||
HWND m_hwndOwner;
|
||||
SonarState m_sonarState = SonarState::Idle;
|
||||
POINT m_lastKeyPos{};
|
||||
DWORD m_lastKeyTime{};
|
||||
|
||||
static constexpr DWORD NoSonar = 0;
|
||||
static constexpr DWORD SonarWaitingForMouseMove = 1;
|
||||
DWORD m_sonarStart = NoSonar;
|
||||
bool m_isSnoopingMouse = false;
|
||||
|
||||
private:
|
||||
static constexpr auto className = L"FindMyMouse";
|
||||
|
||||
// Use the runner name for the Window title. Otherwise, since Find My Mouse has an actual visual, its Window name will be the one shown in Task Manager after being shown.
|
||||
static constexpr auto windowTitle = L"PowerToys Runner";
|
||||
|
||||
static LRESULT CALLBACK s_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
BOOL OnSonarCreate();
|
||||
void OnSonarDestroy();
|
||||
void OnSonarInput(WPARAM flags, HRAWINPUT hInput);
|
||||
void OnSonarKeyboardInput(RAWINPUT const& input);
|
||||
void OnSonarMouseInput(RAWINPUT const& input);
|
||||
void OnMouseTimer();
|
||||
|
||||
void StartSonar();
|
||||
void StopSonar();
|
||||
|
||||
void UpdateMouseSnooping();
|
||||
};
|
||||
|
||||
template<typename D>
|
||||
bool SuperSonar<D>::Initialize(HINSTANCE hinst)
|
||||
{
|
||||
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
|
||||
WNDCLASS wc{};
|
||||
|
||||
if (!GetClassInfoW(hinst, className, &wc))
|
||||
{
|
||||
wc.lpfnWndProc = s_WndProc;
|
||||
wc.hInstance = hinst;
|
||||
wc.hIcon = LoadIcon(hinst, IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
|
||||
wc.lpszClassName = className;
|
||||
|
||||
if (!RegisterClassW(&wc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinst, nullptr);
|
||||
|
||||
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | Shim()->GetExtendedStyle();
|
||||
return CreateWindowExW(exStyle, className, windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hinst, this) != nullptr;
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::Terminate()
|
||||
{
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
DestroyWindow(m_hwndOwner);
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to destroy the sonar Window.");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
LRESULT SuperSonar<D>::s_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
SuperSonar* self;
|
||||
if (message == WM_NCCREATE)
|
||||
{
|
||||
auto info = (LPCREATESTRUCT)lParam;
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)info->lpCreateParams);
|
||||
self = (SuperSonar*)info->lpCreateParams;
|
||||
self->m_hwnd = hwnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
self = (SuperSonar*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
}
|
||||
if (self)
|
||||
{
|
||||
return self->Shim()->WndProc(message, wParam, lParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DefWindowProc(hwnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
LRESULT SuperSonar<D>::BaseWndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
return OnSonarCreate() ? 0 : -1;
|
||||
|
||||
case WM_DESTROY:
|
||||
OnSonarDestroy();
|
||||
break;
|
||||
|
||||
case WM_INPUT:
|
||||
OnSonarInput(wParam, (HRAWINPUT)lParam);
|
||||
break;
|
||||
|
||||
case WM_TIMER:
|
||||
switch (wParam)
|
||||
{
|
||||
case TIMER_ID_TRACK:
|
||||
OnMouseTimer();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_NCHITTEST:
|
||||
return HTTRANSPARENT;
|
||||
}
|
||||
|
||||
return DefWindowProc(m_hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
BOOL SuperSonar<D>::OnSonarCreate()
|
||||
{
|
||||
RAWINPUTDEVICE keyboard{};
|
||||
keyboard.usUsagePage = HID_USAGE_PAGE_GENERIC;
|
||||
keyboard.usUsage = HID_USAGE_GENERIC_KEYBOARD;
|
||||
keyboard.dwFlags = RIDEV_INPUTSINK;
|
||||
keyboard.hwndTarget = m_hwnd;
|
||||
return RegisterRawInputDevices(&keyboard, 1, sizeof(keyboard));
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnSonarDestroy()
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnSonarInput(WPARAM flags, HRAWINPUT hInput)
|
||||
{
|
||||
RAWINPUT input;
|
||||
UINT size = sizeof(input);
|
||||
auto result = GetRawInputData(hInput, RID_INPUT, &input, &size, sizeof(RAWINPUTHEADER));
|
||||
if ((int)result < sizeof(RAWINPUTHEADER))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (input.header.dwType)
|
||||
{
|
||||
case RIM_TYPEKEYBOARD:
|
||||
OnSonarKeyboardInput(input);
|
||||
break;
|
||||
case RIM_TYPEMOUSE:
|
||||
OnSonarMouseInput(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnSonarKeyboardInput(RAWINPUT const& input)
|
||||
{
|
||||
if (input.data.keyboard.VKey != VK_CONTROL)
|
||||
{
|
||||
StopSonar();
|
||||
return;
|
||||
}
|
||||
|
||||
bool pressed = (input.data.keyboard.Flags & RI_KEY_BREAK) == 0;
|
||||
bool rightCtrl = (input.data.keyboard.Flags & RI_KEY_E0) != 0;
|
||||
|
||||
// Deal with rightCtrl first.
|
||||
if (rightCtrl)
|
||||
{
|
||||
/*
|
||||
* SuperSonar originally exited when pressing right control after pressing left control twice.
|
||||
* We take care of exiting FindMyMouse through module disabling in PowerToys settings instead.
|
||||
if (m_sonarState == SonarState::ControlUp2)
|
||||
{
|
||||
Terminate();
|
||||
}
|
||||
*/
|
||||
StopSonar();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_sonarState)
|
||||
{
|
||||
case SonarState::Idle:
|
||||
if (pressed)
|
||||
{
|
||||
m_sonarState = SonarState::ControlDown1;
|
||||
m_lastKeyTime = GetTickCount();
|
||||
m_lastKeyPos = {};
|
||||
GetCursorPos(&m_lastKeyPos);
|
||||
UpdateMouseSnooping();
|
||||
}
|
||||
break;
|
||||
|
||||
case SonarState::ControlDown1:
|
||||
if (!pressed)
|
||||
{
|
||||
m_sonarState = SonarState::ControlUp1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SonarState::ControlUp1:
|
||||
case SonarState::ControlUp2:
|
||||
if (pressed)
|
||||
{
|
||||
m_sonarState = SonarState::ControlDown2;
|
||||
auto now = GetTickCount();
|
||||
POINT ptCursor{};
|
||||
if (GetCursorPos(&ptCursor) &&
|
||||
now - m_lastKeyTime <= GetDoubleClickTime() &&
|
||||
IsEqual(m_lastKeyPos, ptCursor))
|
||||
{
|
||||
StartSonar();
|
||||
}
|
||||
m_lastKeyTime = now;
|
||||
m_lastKeyPos = ptCursor;
|
||||
}
|
||||
break;
|
||||
|
||||
case SonarState::ControlDown2:
|
||||
if (!pressed)
|
||||
{
|
||||
m_sonarState = SonarState::ControlUp2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnSonarMouseInput(RAWINPUT const& input)
|
||||
{
|
||||
if (input.data.mouse.usButtonFlags)
|
||||
{
|
||||
StopSonar();
|
||||
}
|
||||
else if (m_sonarStart != NoSonar)
|
||||
{
|
||||
OnMouseTimer();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::StartSonar()
|
||||
{
|
||||
Logger::info("Focusing the sonar on the mouse cursor.");
|
||||
Trace::MousePointerFocused();
|
||||
// Cover the entire virtual screen.
|
||||
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), 0);
|
||||
m_sonarPos = ptNowhere;
|
||||
OnMouseTimer();
|
||||
UpdateMouseSnooping();
|
||||
Shim()->SetSonarVisibility(true);
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::StopSonar()
|
||||
{
|
||||
if (m_sonarStart != NoSonar)
|
||||
{
|
||||
m_sonarStart = NoSonar;
|
||||
Shim()->SetSonarVisibility(false);
|
||||
KillTimer(m_hwnd, TIMER_ID_TRACK);
|
||||
}
|
||||
m_sonarState = SonarState::Idle;
|
||||
UpdateMouseSnooping();
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnMouseTimer()
|
||||
{
|
||||
auto now = GetTickCount();
|
||||
|
||||
// If mouse has moved, then reset the sonar timer.
|
||||
POINT ptCursor{};
|
||||
if (!GetCursorPos(&ptCursor))
|
||||
{
|
||||
// We are no longer the active desktop - done.
|
||||
StopSonar();
|
||||
return;
|
||||
}
|
||||
ScreenToClient(m_hwnd, &ptCursor);
|
||||
|
||||
if (IsEqual(m_sonarPos, ptCursor))
|
||||
{
|
||||
// Mouse is stationary.
|
||||
if (m_sonarStart != SonarWaitingForMouseMove && now - m_sonarStart >= IdlePeriod)
|
||||
{
|
||||
StopSonar();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mouse has moved.
|
||||
if (IsEqual(m_sonarPos, ptNowhere))
|
||||
{
|
||||
// Initial call, mark sonar as active but waiting for first mouse-move.
|
||||
now = SonarWaitingForMouseMove;
|
||||
}
|
||||
SetTimer(m_hwnd, TIMER_ID_TRACK, IdlePeriod, nullptr);
|
||||
Shim()->BeforeMoveSonar();
|
||||
m_sonarPos = ptCursor;
|
||||
m_sonarStart = now;
|
||||
Shim()->AfterMoveSonar();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::UpdateMouseSnooping()
|
||||
{
|
||||
bool wantSnoopingMouse = m_sonarStart != NoSonar || m_sonarState != SonarState::Idle;
|
||||
if (m_isSnoopingMouse != wantSnoopingMouse)
|
||||
{
|
||||
m_isSnoopingMouse = wantSnoopingMouse;
|
||||
RAWINPUTDEVICE mouse{};
|
||||
mouse.usUsagePage = HID_USAGE_PAGE_GENERIC;
|
||||
mouse.usUsage = HID_USAGE_GENERIC_MOUSE;
|
||||
if (wantSnoopingMouse)
|
||||
{
|
||||
mouse.dwFlags = RIDEV_INPUTSINK;
|
||||
mouse.hwndTarget = m_hwnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse.dwFlags = RIDEV_REMOVE;
|
||||
mouse.hwndTarget = nullptr;
|
||||
}
|
||||
RegisterRawInputDevices(&mouse, 1, sizeof(mouse));
|
||||
}
|
||||
}
|
||||
|
||||
struct CompositionSpotlight : SuperSonar<CompositionSpotlight>
|
||||
{
|
||||
static constexpr UINT WM_OPACITY_ANIMATION_COMPLETED = WM_APP;
|
||||
static constexpr float SonarRadiusFloat = static_cast<float>(SonarRadius);
|
||||
|
||||
DWORD GetExtendedStyle()
|
||||
{
|
||||
return WS_EX_NOREDIRECTIONBITMAP;
|
||||
}
|
||||
|
||||
void AfterMoveSonar()
|
||||
{
|
||||
m_spotlight.Offset({ (float)m_sonarPos.x, (float)m_sonarPos.y, 0.0f });
|
||||
}
|
||||
|
||||
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
return OnCompositionCreate() && BaseWndProc(message, wParam, lParam);
|
||||
|
||||
case WM_OPACITY_ANIMATION_COMPLETED:
|
||||
OnOpacityAnimationCompleted();
|
||||
break;
|
||||
}
|
||||
return BaseWndProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
void SetSonarVisibility(bool visible)
|
||||
{
|
||||
m_batch = m_compositor.GetCommitBatch(winrt::CompositionBatchTypes::Animation);
|
||||
m_batch.Completed([hwnd = m_hwnd](auto&&, auto&&) {
|
||||
PostMessage(hwnd, WM_OPACITY_ANIMATION_COMPLETED, 0, 0);
|
||||
});
|
||||
m_root.Opacity(visible ? static_cast<float>(FinalAlphaNumerator) / FinalAlphaDenominator : 0.0f);
|
||||
if (visible)
|
||||
{
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool OnCompositionCreate()
|
||||
try
|
||||
{
|
||||
// We need a dispatcher queue.
|
||||
DispatcherQueueOptions options = {
|
||||
sizeof(options),
|
||||
DQTYPE_THREAD_CURRENT,
|
||||
DQTAT_COM_ASTA,
|
||||
};
|
||||
ABI::IDispatcherQueueController* controller;
|
||||
winrt::check_hresult(CreateDispatcherQueueController(options, &controller));
|
||||
*winrt::put_abi(m_dispatcherQueueController) = controller;
|
||||
|
||||
// Create the compositor for our window.
|
||||
m_compositor = winrt::Compositor();
|
||||
ABI::IDesktopWindowTarget* target;
|
||||
winrt::check_hresult(m_compositor.as<ABI::ICompositorDesktopInterop>()->CreateDesktopWindowTarget(m_hwnd, false, &target));
|
||||
*winrt::put_abi(m_target) = target;
|
||||
|
||||
// Our composition tree:
|
||||
//
|
||||
// [root] ContainerVisual
|
||||
// \ LayerVisual
|
||||
// \[gray backdrop]
|
||||
// [spotlight]
|
||||
m_root = m_compositor.CreateContainerVisual();
|
||||
m_root.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_root.Opacity(0.0f);
|
||||
m_target.Root(m_root);
|
||||
|
||||
auto layer = m_compositor.CreateLayerVisual();
|
||||
layer.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_root.Children().InsertAtTop(layer);
|
||||
|
||||
auto backdrop = m_compositor.CreateSpriteVisual();
|
||||
backdrop.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
backdrop.Brush(m_compositor.CreateColorBrush({ 255, 0, 0, 0 }));
|
||||
layer.Children().InsertAtTop(backdrop);
|
||||
|
||||
m_circleGeometry = m_compositor.CreateEllipseGeometry(); // radius set via expression animation
|
||||
auto circleShape = m_compositor.CreateSpriteShape(m_circleGeometry);
|
||||
circleShape.FillBrush(m_compositor.CreateColorBrush({ 255, 255, 255, 255 }));
|
||||
circleShape.Offset({ SonarRadiusFloat * SonarZoomFactor, SonarRadiusFloat * SonarZoomFactor });
|
||||
m_spotlight = m_compositor.CreateShapeVisual();
|
||||
m_spotlight.Size({ SonarRadiusFloat * 2 * SonarZoomFactor, SonarRadiusFloat * 2 * SonarZoomFactor });
|
||||
m_spotlight.AnchorPoint({ 0.5f, 0.5f });
|
||||
m_spotlight.Shapes().Append(circleShape);
|
||||
|
||||
layer.Children().InsertAtTop(m_spotlight);
|
||||
|
||||
// Implicitly animate the alpha.
|
||||
auto animation = m_compositor.CreateScalarKeyFrameAnimation();
|
||||
animation.Target(L"Opacity");
|
||||
animation.InsertExpressionKeyFrame(1.0f, L"this.FinalValue");
|
||||
animation.Duration(std::chrono::milliseconds{ FadeDuration });
|
||||
auto collection = m_compositor.CreateImplicitAnimationCollection();
|
||||
collection.Insert(L"Opacity", animation);
|
||||
m_root.ImplicitAnimations(collection);
|
||||
|
||||
// Radius of spotlight shrinks as opacity increases.
|
||||
// At opacity zero, it is SonarRadius * SonarZoomFactor.
|
||||
// At maximum opacity, it is SonarRadius.
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", SonarRadius * SonarZoomFactor, SonarRadius * SonarZoomFactor, SonarRadius, SonarRadius, FinalAlphaDenominator, FinalAlphaNumerator));
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnOpacityAnimationCompleted()
|
||||
{
|
||||
if (m_root.Opacity() < 0.01f)
|
||||
{
|
||||
ShowWindow(m_hwnd, SW_HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
winrt::Compositor m_compositor{ nullptr };
|
||||
winrt::Desktop::DesktopWindowTarget m_target{ nullptr };
|
||||
winrt::ContainerVisual m_root{ nullptr };
|
||||
winrt::CompositionEllipseGeometry m_circleGeometry{ nullptr };
|
||||
winrt::ShapeVisual m_spotlight{ nullptr };
|
||||
winrt::CompositionCommitBatch m_batch{ nullptr };
|
||||
};
|
||||
|
||||
template<typename D>
|
||||
struct GdiSonar : SuperSonar<D>
|
||||
{
|
||||
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
SetLayeredWindowAttributes(this->m_hwnd, 0, 0, LWA_ALPHA);
|
||||
break;
|
||||
|
||||
case WM_TIMER:
|
||||
switch (wParam)
|
||||
{
|
||||
case TIMER_ID_FADE:
|
||||
OnFadeTimer();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
this->Shim()->OnPaint();
|
||||
break;
|
||||
}
|
||||
return this->BaseWndProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
void BeforeMoveSonar() { this->Shim()->InvalidateSonar(); }
|
||||
void AfterMoveSonar() { this->Shim()->InvalidateSonar(); }
|
||||
|
||||
void SetSonarVisibility(bool visible)
|
||||
{
|
||||
m_alphaTarget = visible ? MaxAlpha : 0;
|
||||
m_fadeStart = GetTickCount() - FadeFramePeriod;
|
||||
SetTimer(this->m_hwnd, TIMER_ID_FADE, FadeFramePeriod, nullptr);
|
||||
OnFadeTimer();
|
||||
}
|
||||
|
||||
void OnFadeTimer()
|
||||
{
|
||||
auto now = GetTickCount();
|
||||
auto step = (int)((now - m_fadeStart) * MaxAlpha / this->FadeDuration);
|
||||
|
||||
this->Shim()->InvalidateSonar();
|
||||
if (m_alpha < m_alphaTarget)
|
||||
{
|
||||
m_alpha += step;
|
||||
if (m_alpha > m_alphaTarget)
|
||||
m_alpha = m_alphaTarget;
|
||||
}
|
||||
else if (m_alpha > m_alphaTarget)
|
||||
{
|
||||
m_alpha -= step;
|
||||
if (m_alpha < m_alphaTarget)
|
||||
m_alpha = m_alphaTarget;
|
||||
}
|
||||
SetLayeredWindowAttributes(this->m_hwnd, 0, (BYTE)m_alpha, LWA_ALPHA);
|
||||
this->Shim()->InvalidateSonar();
|
||||
if (m_alpha == m_alphaTarget)
|
||||
{
|
||||
KillTimer(this->m_hwnd, TIMER_ID_FADE);
|
||||
if (m_alpha == 0)
|
||||
{
|
||||
ShowWindow(this->m_hwnd, SW_HIDE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowWindow(this->m_hwnd, SW_SHOWNOACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
int CurrentSonarRadius()
|
||||
{
|
||||
int range = MaxAlpha - m_alpha;
|
||||
int radius = this->SonarRadius + this->SonarRadius * range * (this->SonarZoomFactor - 1) / MaxAlpha;
|
||||
return radius;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr DWORD FadeFramePeriod = 10;
|
||||
static constexpr int MaxAlpha = SuperSonar<D>::FinalAlphaNumerator * 255 / SuperSonar<D>::FinalAlphaDenominator;
|
||||
static constexpr DWORD TIMER_ID_FADE = 101;
|
||||
|
||||
private:
|
||||
int m_alpha = 0;
|
||||
int m_alphaTarget = 0;
|
||||
DWORD m_fadeStart = 0;
|
||||
};
|
||||
|
||||
struct GdiSpotlight : GdiSonar<GdiSpotlight>
|
||||
{
|
||||
void InvalidateSonar()
|
||||
{
|
||||
RECT rc;
|
||||
auto radius = CurrentSonarRadius();
|
||||
rc.left = this->m_sonarPos.x - radius;
|
||||
rc.top = this->m_sonarPos.y - radius;
|
||||
rc.right = this->m_sonarPos.x + radius;
|
||||
rc.bottom = this->m_sonarPos.y + radius;
|
||||
InvalidateRect(this->m_hwnd, &rc, FALSE);
|
||||
}
|
||||
|
||||
void OnPaint()
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(this->m_hwnd, &ps);
|
||||
|
||||
auto radius = CurrentSonarRadius();
|
||||
auto spotlight = CreateRoundRectRgn(
|
||||
this->m_sonarPos.x - radius, this->m_sonarPos.y - radius, this->m_sonarPos.x + radius, this->m_sonarPos.y + radius, radius * 2, radius * 2);
|
||||
|
||||
FillRgn(ps.hdc, spotlight, (HBRUSH)GetStockObject(WHITE_BRUSH));
|
||||
Sleep(1000 / 60);
|
||||
ExtSelectClipRgn(ps.hdc, spotlight, RGN_DIFF);
|
||||
FillRect(ps.hdc, &ps.rcPaint, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
||||
DeleteObject(spotlight);
|
||||
|
||||
EndPaint(this->m_hwnd, &ps);
|
||||
}
|
||||
};
|
||||
|
||||
struct GdiCrosshairs : GdiSonar<GdiCrosshairs>
|
||||
{
|
||||
void InvalidateSonar()
|
||||
{
|
||||
RECT rc;
|
||||
auto radius = CurrentSonarRadius();
|
||||
GetClientRect(m_hwnd, &rc);
|
||||
rc.left = m_sonarPos.x - radius;
|
||||
rc.right = m_sonarPos.x + radius;
|
||||
InvalidateRect(m_hwnd, &rc, FALSE);
|
||||
|
||||
GetClientRect(m_hwnd, &rc);
|
||||
rc.top = m_sonarPos.y - radius;
|
||||
rc.bottom = m_sonarPos.y + radius;
|
||||
InvalidateRect(m_hwnd, &rc, FALSE);
|
||||
}
|
||||
|
||||
void OnPaint()
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(this->m_hwnd, &ps);
|
||||
|
||||
auto radius = CurrentSonarRadius();
|
||||
RECT rc;
|
||||
|
||||
HBRUSH white = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
||||
|
||||
rc.left = m_sonarPos.x - radius;
|
||||
rc.top = ps.rcPaint.top;
|
||||
rc.right = m_sonarPos.x + radius;
|
||||
rc.bottom = ps.rcPaint.bottom;
|
||||
FillRect(ps.hdc, &rc, white);
|
||||
|
||||
rc.left = ps.rcPaint.left;
|
||||
rc.top = m_sonarPos.y - radius;
|
||||
rc.right = ps.rcPaint.right;
|
||||
rc.bottom = m_sonarPos.y + radius;
|
||||
FillRect(ps.hdc, &rc, white);
|
||||
|
||||
HBRUSH black = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
|
||||
// Top left
|
||||
rc.left = ps.rcPaint.left;
|
||||
rc.top = ps.rcPaint.top;
|
||||
rc.right = m_sonarPos.x - radius;
|
||||
rc.bottom = m_sonarPos.y - radius;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
// Top right
|
||||
rc.left = m_sonarPos.x + radius;
|
||||
rc.top = ps.rcPaint.top;
|
||||
rc.right = ps.rcPaint.right;
|
||||
rc.bottom = m_sonarPos.y - radius;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
// Bottom left
|
||||
rc.left = ps.rcPaint.left;
|
||||
rc.top = m_sonarPos.y + radius;
|
||||
rc.right = m_sonarPos.x - radius;
|
||||
rc.bottom = ps.rcPaint.bottom;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
// Bottom right
|
||||
rc.left = m_sonarPos.x + radius;
|
||||
rc.top = m_sonarPos.y + radius;
|
||||
rc.right = ps.rcPaint.right;
|
||||
rc.bottom = ps.rcPaint.bottom;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
EndPaint(this->m_hwnd, &ps);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma endregion Super_Sonar_Base_Code
|
||||
|
||||
|
||||
#pragma region Super_Sonar_API
|
||||
|
||||
CompositionSpotlight* m_sonar = nullptr;
|
||||
|
||||
void FindMyMouseDisable()
|
||||
{
|
||||
if (m_sonar != nullptr)
|
||||
{
|
||||
Logger::info("Terminating a sonar instance.");
|
||||
m_sonar->Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool FindMyMouseIsEnabled()
|
||||
{
|
||||
return (m_sonar != nullptr);
|
||||
}
|
||||
|
||||
// Based on SuperSonar's original wWinMain.
|
||||
int FindMyMouseMain(HINSTANCE hinst)
|
||||
{
|
||||
Logger::info("Starting a sonar instance.");
|
||||
if (m_sonar != nullptr)
|
||||
{
|
||||
Logger::error("A sonar instance was still working when trying to start a new one.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
CompositionSpotlight sonar;
|
||||
if (!sonar.Initialize(hinst))
|
||||
{
|
||||
Logger::error("Couldn't initialize a sonar instance.");
|
||||
return 0;
|
||||
}
|
||||
m_sonar = &sonar;
|
||||
Logger::info("Initialized the sonar instance.");
|
||||
|
||||
MSG msg;
|
||||
|
||||
// Main message loop:
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
Logger::info("Sonar message loop ended.");
|
||||
m_sonar = nullptr;
|
||||
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
|
||||
#pragma endregion Super_Sonar_API
|
6
src/modules/MouseUtils/FindMyMouse/FindMyMouse.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
int FindMyMouseMain(HINSTANCE hinst);
|
||||
void FindMyMouseDisable();
|
||||
bool FindMyMouseIsEnabled();
|
||||
|
146
src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj
Normal file
@ -0,0 +1,146 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{e94fd11c-0591-456f-899f-efc0ca548336}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>FindMyMouse</RootNamespace>
|
||||
<OverrideWindowsTargetPlatformVersion>true</OverrideWindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>FindMyMouse</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(CIBuild)'!='true'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="FindMyMouse.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Generated Files\resource.h" />
|
||||
<None Include="resource.base.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="FindMyMouse.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<None Include="FindMyMouse.base.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\FindMyMouse.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
@ -0,0 +1,62 @@
|
||||
<?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++;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>{875a08c6-f610-4667-bd0f-80171ed96072}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FindMyMouse.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FindMyMouse.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Generated Files\resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="resource.base.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="FindMyMouse.base.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\FindMyMouse.rc">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
148
src/modules/MouseUtils/FindMyMouse/dllmain.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include "trace.h"
|
||||
#include "FindMyMouse.h"
|
||||
#include <thread>
|
||||
#include <common/utils/logger_helper.h>
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
HMODULE m_hModule;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
m_hModule = hModule;
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The PowerToy name that will be shown in the settings.
|
||||
const static wchar_t* MODULE_NAME = L"FindMyMouse";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"Focus the mouse pointer";
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class FindMyMouse : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
// Load initial settings from the persisted values.
|
||||
void init_settings();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
FindMyMouse()
|
||||
{
|
||||
LoggerHelpers::init_logger(MODULE_NAME, L"ModuleInterface", LogSettings::findMyMouseLoggerName);
|
||||
init_settings();
|
||||
};
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the localized display name of the powertoy
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
// Create a Settings object.
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
settings.set_description(MODULE_DESC);
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
// This can be used to spawn more complex editors.
|
||||
virtual void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the input JSON string.
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Improper JSON.
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
Trace::EnableFindMyMouse(true);
|
||||
std::thread([]() { FindMyMouseMain(m_hModule); }).detach();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
Trace::EnableFindMyMouse(false);
|
||||
FindMyMouseDisable();
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
};
|
||||
|
||||
// Load the settings file.
|
||||
void FindMyMouse::init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(FindMyMouse::get_key());
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Error while loading from the settings file. Let default values stay as they are.
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new FindMyMouse();
|
||||
}
|
4
src/modules/MouseUtils/FindMyMouse/packages.config
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
|
||||
</packages>
|
1
src/modules/MouseUtils/FindMyMouse/pch.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "pch.h"
|
20
src/modules/MouseUtils/FindMyMouse/pch.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#define COMPOSITION
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <windows.h>
|
||||
#include <strsafe.h>
|
||||
#include <hIdUsage.h>
|
||||
|
||||
#ifdef COMPOSITION
|
||||
#include <windows.ui.composition.interop.h>
|
||||
#include <DispatcherQueue.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.UI.Composition.Desktop.h>
|
||||
#endif
|
||||
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
14
src/modules/MouseUtils/FindMyMouse/resource.base.h
Normal file
@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by FindMyMouse.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys FindMyMouse"
|
||||
#define INTERNAL_NAME "FindMyMouse"
|
||||
#define ORIGINAL_FILENAME "FindMyMouse.dll"
|
||||
#define IDS_KEYBOARDMANAGER_ICON 1001
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
40
src/modules/MouseUtils/FindMyMouse/trace.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
// Log if the user has FindMyMouse enabled or disabled
|
||||
void Trace::EnableFindMyMouse(const bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"FindMyMouse_EnableFindMyMouse",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
// Log that the user activated the module by focusing the mouse pointer
|
||||
void Trace::MousePointerFocused() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"FindMyMouse_MousePointerFocused",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
14
src/modules/MouseUtils/FindMyMouse/trace.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider() noexcept;
|
||||
static void UnregisterProvider() noexcept;
|
||||
|
||||
// Log if the user has FindMyMouse enabled or disabled
|
||||
static void EnableFindMyMouse(const bool enabled) noexcept;
|
||||
|
||||
// Log that the user activated the module by focusing the mouse pointer
|
||||
static void MousePointerFocused() noexcept;
|
||||
};
|
@ -147,7 +147,8 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
||||
L"modules/PowerRename/PowerRenameExt.dll",
|
||||
L"modules/ShortcutGuide/ShortcutGuideModuleInterface/ShortcutGuideModuleInterface.dll",
|
||||
L"modules/ColorPicker/ColorPicker.dll",
|
||||
L"modules/Awake/AwakeModuleInterface.dll"
|
||||
L"modules/Awake/AwakeModuleInterface.dll",
|
||||
L"modules/MouseUtils/FindMyMouse.dll"
|
||||
|
||||
};
|
||||
const auto VCM_PATH = L"modules/VideoConference/VideoConferenceModule.dll";
|
||||
|
@ -523,6 +523,8 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
|
||||
return "ImageResizer";
|
||||
case ESettingsWindowNames::KBM:
|
||||
return "KBM";
|
||||
case ESettingsWindowNames::MouseUtils:
|
||||
return "MouseUtils";
|
||||
case ESettingsWindowNames::PowerRename:
|
||||
return "PowerRename";
|
||||
case ESettingsWindowNames::FileExplorer:
|
||||
@ -570,6 +572,10 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
|
||||
{
|
||||
return ESettingsWindowNames::KBM;
|
||||
}
|
||||
else if (value == "MouseUtils")
|
||||
{
|
||||
return ESettingsWindowNames::MouseUtils;
|
||||
}
|
||||
else if (value == "PowerRename")
|
||||
{
|
||||
return ESettingsWindowNames::PowerRename;
|
||||
|
@ -11,6 +11,7 @@ enum class ESettingsWindowNames
|
||||
Run,
|
||||
ImageResizer,
|
||||
KBM,
|
||||
MouseUtils,
|
||||
PowerRename,
|
||||
FileExplorer,
|
||||
ShortcutGuide,
|
||||
|
@ -175,6 +175,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool findMyMouse = true;
|
||||
|
||||
[JsonPropertyName("FindMyMouse")]
|
||||
public bool FindMyMouse
|
||||
{
|
||||
get => findMyMouse;
|
||||
set
|
||||
{
|
||||
if (findMyMouse != value)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
findMyMouse = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string ToJsonString()
|
||||
{
|
||||
return JsonSerializer.Serialize(this);
|
||||
|
@ -0,0 +1,56 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
{
|
||||
public class MouseUtilsViewModel : Observable
|
||||
{
|
||||
private GeneralSettings GeneralSettingsConfig { get; set; }
|
||||
|
||||
public MouseUtilsViewModel(ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
||||
{
|
||||
// To obtain the general settings configurations of PowerToys Settings.
|
||||
if (settingsRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(settingsRepository));
|
||||
}
|
||||
|
||||
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
||||
|
||||
_isFindMyMouseEnabled = GeneralSettingsConfig.Enabled.FindMyMouse;
|
||||
|
||||
// set the callback functions value to hangle outgoing IPC message.
|
||||
SendConfigMSG = ipcMSGCallBackFunc;
|
||||
}
|
||||
|
||||
public bool IsFindMyMouseEnabled
|
||||
{
|
||||
get => _isFindMyMouseEnabled;
|
||||
set
|
||||
{
|
||||
if (_isFindMyMouseEnabled != value)
|
||||
{
|
||||
_isFindMyMouseEnabled = value;
|
||||
|
||||
GeneralSettingsConfig.Enabled.FindMyMouse = value;
|
||||
OnPropertyChanged(nameof(IsFindMyMouseEnabled));
|
||||
|
||||
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
SendConfigMSG(outgoing.ToString());
|
||||
|
||||
// TODO: Implement when this module has properties.
|
||||
// NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Func<string, int> SendConfigMSG { get; }
|
||||
|
||||
private bool _isFindMyMouseEnabled;
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 1.4 MiB |
@ -155,6 +155,9 @@
|
||||
<Compile Include="OOBE\Views\OobeKBM.xaml.cs">
|
||||
<DependentUpon>OobeKBM.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="OOBE\Views\OobeMouseUtils.xaml.cs">
|
||||
<DependentUpon>OobeMouseUtils.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="OOBE\Views\OobeOverview.xaml.cs">
|
||||
<DependentUpon>OobeOverview.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -192,6 +195,9 @@
|
||||
<Compile Include="Views\KeyboardManagerPage.xaml.cs">
|
||||
<DependentUpon>KeyboardManagerPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\MouseUtilsPage.xaml.cs">
|
||||
<DependentUpon>MouseUtilsPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\PowerLauncherPage.xaml.cs">
|
||||
<DependentUpon>PowerLauncherPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -227,6 +233,7 @@
|
||||
<Content Include="Assets\FluentIcons\FluentIconsFileExplorerPreview.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsImageResizer.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsKeyboardManager.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsMouseUtils.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsPowerRename.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsPowerToys.png" />
|
||||
<Content Include="Assets\FluentIcons\FluentIconsPowerToysRun.png" />
|
||||
@ -239,12 +246,14 @@
|
||||
<Content Include="Assets\Modules\FancyZones.png" />
|
||||
<Content Include="Assets\Modules\ImageResizer.png" />
|
||||
<Content Include="Assets\Modules\KBM.png" />
|
||||
<Content Include="Assets\Modules\MouseUtils.png" />
|
||||
<Content Include="Assets\Modules\OOBE\ColorPicker.gif" />
|
||||
<Content Include="Assets\Modules\OOBE\Awake.png" />
|
||||
<Content Include="Assets\Modules\OOBE\FancyZones.gif" />
|
||||
<Content Include="Assets\Modules\OOBE\FileExplorer.png" />
|
||||
<Content Include="Assets\Modules\OOBE\ImageResizer.gif" />
|
||||
<Content Include="Assets\Modules\OOBE\KBM.gif" />
|
||||
<Content Include="Assets\Modules\OOBE\MouseUtils.gif" />
|
||||
<Content Include="Assets\Modules\OOBE\OOBEPTHero.png" />
|
||||
<Content Include="Assets\Modules\OOBE\PowerRename.gif" />
|
||||
<Content Include="Assets\Modules\OOBE\Run.gif" />
|
||||
@ -365,6 +374,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="OOBE\Views\OobeMouseUtils.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="OOBE\Views\OobeOverview.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@ -429,6 +442,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\MouseUtilsPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\PowerLauncherPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
@ -13,6 +13,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Enums
|
||||
FileExplorer,
|
||||
ImageResizer,
|
||||
KBM,
|
||||
MouseUtils,
|
||||
PowerRename,
|
||||
Run,
|
||||
ShortcutGuide,
|
||||
|
@ -0,0 +1,33 @@
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobeMouseUtils"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:toolkitcontrols="using:Microsoft.Toolkit.Uwp.UI.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<controls:OOBEPageControl ModuleTitle="{x:Bind ViewModel.ModuleName}"
|
||||
ModuleImageSource="{x:Bind ViewModel.PreviewImageSource}"
|
||||
ModuleDescription="{x:Bind ViewModel.Description}">
|
||||
|
||||
<controls:OOBEPageControl.ModuleContent>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock x:Uid="Oobe_MouseUtils_FindMyMouse"
|
||||
Style="{ThemeResource OobeSubtitleStyle}" />
|
||||
<toolkitcontrols:MarkdownTextBlock Background="Transparent" x:Uid="Oobe_MouseUtils_FindMyMouse_Description" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="12" Margin="0,24,0,0">
|
||||
<Button x:Uid="OOBE_Settings"
|
||||
Click="SettingsLaunchButton_Click"/>
|
||||
<HyperlinkButton NavigateUri="{x:Bind ViewModel.Link}" Style="{StaticResource TextButtonStyle}">
|
||||
<TextBlock x:Uid="LearnMore_MouseUtils"
|
||||
TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</controls:OOBEPageControl.ModuleContent>
|
||||
</controls:OOBEPageControl>
|
||||
</Page>
|
@ -0,0 +1,45 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
public sealed partial class OobeMouseUtils : Page
|
||||
{
|
||||
public OobePowerToysModule ViewModel { get; set; }
|
||||
|
||||
public OobeMouseUtils()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.MouseUtils]);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (OobeShellPage.OpenMainWindowCallback != null)
|
||||
{
|
||||
OobeShellPage.OpenMainWindowCallback(typeof(MouseUtilsPage));
|
||||
}
|
||||
|
||||
ViewModel.LogOpeningSettingsEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogClosingModuleEvent();
|
||||
}
|
||||
}
|
||||
}
|
@ -143,6 +143,18 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/KBM.gif",
|
||||
Link = "https://aka.ms/PowerToysOverview_KeyboardManager",
|
||||
});
|
||||
Modules.Insert((int)PowerToysModulesEnum.MouseUtils, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = loader.GetString("Oobe_MouseUtils"),
|
||||
Tag = "MouseUtils",
|
||||
IsNew = true,
|
||||
Icon = "\uE962",
|
||||
FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsMouseUtils.png",
|
||||
Image = "ms-appx:///Assets/Modules/MouseUtils.png",
|
||||
Description = loader.GetString("Oobe_MouseUtils_Description"),
|
||||
PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/MouseUtils.gif",
|
||||
Link = "https://aka.ms/PowerToysOverview_MouseUtilities", // TODO: Add correct link after it's been created.
|
||||
});
|
||||
Modules.Insert((int)PowerToysModulesEnum.PowerRename, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = loader.GetString("Oobe_PowerRename"),
|
||||
@ -228,6 +240,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
case "FileExplorer": NavigationFrame.Navigate(typeof(OobeFileExplorer)); break;
|
||||
case "ShortcutGuide": NavigationFrame.Navigate(typeof(OobeShortcutGuide)); break;
|
||||
case "VideoConference": NavigationFrame.Navigate(typeof(OobeVideoConference)); break;
|
||||
case "MouseUtils": NavigationFrame.Navigate(typeof(OobeMouseUtils)); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,6 +248,10 @@
|
||||
<value>Keyboard Manager</value>
|
||||
<comment>Product name: Navigation view item name for Keyboard Manager</comment>
|
||||
</data>
|
||||
<data name="Shell_MouseUtilities.Content" xml:space="preserve">
|
||||
<value>Mouse utilities</value>
|
||||
<comment>Product name: Navigation view item name for Mouse utilities</comment>
|
||||
</data>
|
||||
<data name="Shell_NavigationMenu_Announce_Collapse" xml:space="preserve">
|
||||
<value>Navigation closed</value>
|
||||
<comment>Accessibility announcement when the navigation pane collapses</comment>
|
||||
@ -1275,6 +1279,10 @@ Made with 💗 by Microsoft and the PowerToys community.</value>
|
||||
<data name="Oobe_VideoConference_Description" xml:space="preserve">
|
||||
<value>Video Conference Mute allows users to quickly mute the microphone and turn off the camera while on a conference call with a single keystroke, regardless of what application has focus on your computer.</value>
|
||||
</data>
|
||||
<data name="Oobe_MouseUtils_Description" xml:space="preserve">
|
||||
<value>A collection of utilities to enhance your mouse.</value>
|
||||
<comment>Mouse as in the hardware peripheral</comment>
|
||||
</data>
|
||||
<data name="Oobe_Overview_Description.Text" xml:space="preserve">
|
||||
<value>Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity.
|
||||
|
||||
@ -1567,6 +1575,10 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
|
||||
<value>Learn more about Keyboard Manager</value>
|
||||
<comment>Keyboard Manager is a product name, do not loc</comment>
|
||||
</data>
|
||||
<data name="LearnMore_MouseUtils.Text" xml:space="preserve">
|
||||
<value>Learn more about Mouse utilities</value>
|
||||
<comment>Mouse utilities is a product name, do not loc</comment>
|
||||
</data>
|
||||
<data name="LearnMore_PowerPreview.Text" xml:space="preserve">
|
||||
<value>Learn more about File Explorer add-ons</value>
|
||||
<comment>File Explorer is a product name, do not loc</comment>
|
||||
@ -1591,6 +1603,18 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
|
||||
<value>File Explorer add-ons</value>
|
||||
<comment>Do not localize this string</comment>
|
||||
</data>
|
||||
<data name="Oobe_MouseUtils" xml:space="preserve">
|
||||
<value>Mouse utilities</value>
|
||||
<comment>Mouse as in the hardware peripheral</comment>
|
||||
</data>
|
||||
<data name="Oobe_MouseUtils_FindMyMouse.Text" xml:space="preserve">
|
||||
<value>Find My Mouse</value>
|
||||
<comment>Mouse as in the hardware peripheral</comment>
|
||||
</data>
|
||||
<data name="Oobe_MouseUtils_FindMyMouse_Description.Text" xml:space="preserve">
|
||||
<value>Click twice on the Left Control key to focus on your mouse.</value>
|
||||
<comment>Mouse as in the hardware peripheral. Key as in a keyboard key</comment>
|
||||
</data>
|
||||
<data name="Launch_Run.Content" xml:space="preserve">
|
||||
<value>Launch PowerToys Run</value>
|
||||
</data>
|
||||
@ -1621,6 +1645,9 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
|
||||
<data name="ImageResizer.SecondaryLinksHeader" xml:space="preserve">
|
||||
<value>Attribution</value>
|
||||
</data>
|
||||
<data name="MouseUtils.SecondaryLinksHeader" xml:space="preserve">
|
||||
<value>Attribution</value>
|
||||
</data>
|
||||
<data name="PowerLauncher.SecondaryLinksHeader" xml:space="preserve">
|
||||
<value>Attribution</value>
|
||||
</data>
|
||||
@ -1661,4 +1688,18 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
|
||||
<data name="Awake_TimeBeforeAwake.Header" xml:space="preserve">
|
||||
<value>Time before returning to the previous awakeness state</value>
|
||||
</data>
|
||||
<data name="MouseUtils.ModuleTitle" xml:space="preserve">
|
||||
<value>Mouse utilities</value>
|
||||
</data>
|
||||
<data name="MouseUtils.ModuleDescription" xml:space="preserve">
|
||||
<value>A collection of mouse utilities.</value>
|
||||
</data>
|
||||
<data name="MouseUtils_Enable_FindMyMouse.Header" xml:space="preserve">
|
||||
<value>Enable Find My Mouse</value>
|
||||
<comment>"Find My Mouse" is the name of the utility.</comment>
|
||||
</data>
|
||||
<data name="MouseUtils_Enable_FindMyMouse.Description" xml:space="preserve">
|
||||
<value>Press the Left Control key twice to focus the mouse pointer.</value>
|
||||
<comment>"Left Control" is a keyboard key.</comment>
|
||||
</data>
|
||||
</root>
|
@ -0,0 +1,32 @@
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.MouseUtilsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
AutomationProperties.LandmarkType="Main">
|
||||
|
||||
<controls:SettingsPageControl x:Uid="MouseUtils"
|
||||
ModuleImageSource="ms-appx:///Assets/Modules/MouseUtils.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel Orientation="Vertical">
|
||||
|
||||
<controls:Setting x:Uid="MouseUtils_Enable_FindMyMouse" Icon="">
|
||||
<controls:Setting.ActionContent>
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.IsFindMyMouseEnabled, Mode=TwoWay}" HorizontalAlignment="Right"/>
|
||||
</controls:Setting.ActionContent>
|
||||
</controls:Setting>
|
||||
|
||||
</StackPanel>
|
||||
</controls:SettingsPageControl.ModuleContent>
|
||||
<controls:SettingsPageControl.PrimaryLinks>
|
||||
<controls:PageLink x:Uid="LearnMore_MouseUtils" Link="https://aka.ms/PowerToysOverview_MouseUtilities"/>
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
<controls:SettingsPageControl.SecondaryLinks>
|
||||
<controls:PageLink Text="Raymond Chen's Find My Mouse" Link="https://devblogs.microsoft.com/oldnewthing/author/oldnewthing"/>
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.ViewModels;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class MouseUtilsPage : Page
|
||||
{
|
||||
private MouseUtilsViewModel ViewModel { get; set; }
|
||||
|
||||
public MouseUtilsPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
ViewModel = new MouseUtilsViewModel(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
@ -95,6 +95,14 @@
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
|
||||
<muxc:NavigationViewItem x:Uid="Shell_MouseUtilities"
|
||||
helpers:NavHelper.NavigateTo="views:MouseUtilsPage">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<BitmapIcon UriSource="ms-appx:///Assets/FluentIcons/FluentIconsMouseUtils.png"
|
||||
ShowAsMonochrome="False" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
|
||||
<muxc:NavigationViewItem x:Uid="Shell_PowerRename"
|
||||
helpers:NavHelper.NavigateTo="views:PowerRenamePage">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
|
@ -68,6 +68,7 @@ namespace PowerToys.Settings
|
||||
case "Run": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.PowerLauncherPage); break;
|
||||
case "ImageResizer": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.ImageResizerPage); break;
|
||||
case "KBM": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.KeyboardManagerPage); break;
|
||||
case "MouseUtils": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.MouseUtilsPage); break;
|
||||
case "PowerRename": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.PowerRenamePage); break;
|
||||
case "FileExplorer": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.PowerPreviewPage); break;
|
||||
case "ShortcutGuide": app.StartupPage = typeof(Microsoft.PowerToys.Settings.UI.Views.ShortcutGuidePage); break;
|
||||
|