mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 19:27:56 +01:00
More deux, two
This commit is contained in:
@@ -365,6 +365,7 @@
|
||||
<Project Path="src/modules/Deux/SDK/Microsoft.CommandPalette.Extensions/Microsoft.CommandPalette.Extensions.vcxproj" Id="7997dad4-31d6-496b-95db-6c028d699370" />
|
||||
</Folder>
|
||||
<Folder Name="/modules/Deux/UI/">
|
||||
<Project Path="src/modules/Deux/UI/CmdPalKeyboardService/CmdPalKeyboardService.vcxproj" Id="fc192bce-bfbb-40f5-8c2d-9858de12c31f" />
|
||||
<Project Path="src/modules/Deux/UI/Microsoft.CommandPalette.UI.Models/Microsoft.CommandPalette.UI.Models.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
EXPORTS
|
||||
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
|
||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
||||
@@ -0,0 +1,176 @@
|
||||
<?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.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
|
||||
<CppWinRTGenerateWindowsMetadata>true</CppWinRTGenerateWindowsMetadata>
|
||||
<ProjectGuid>{FC192BCE-BFBB-40F5-8C2D-9858DE12C31F}</ProjectGuid>
|
||||
<ProjectName>CmdPalKeyboardService</ProjectName>
|
||||
<RootNamespace>CmdPalKeyboardService</RootNamespace>
|
||||
<AppxPackage>false</AppxPackage>
|
||||
</PropertyGroup>
|
||||
<!-- BEGIN common.build.pre.props -->
|
||||
<PropertyGroup Label="Configuration">
|
||||
<EnableHybridCRT>true</EnableHybridCRT>
|
||||
<UseCrtSDKReferenceStaticWarning Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReferenceStaticWarning>
|
||||
</PropertyGroup>
|
||||
<!-- END common.build.pre.props -->
|
||||
<!-- BEGIN cppwinrt.build.pre.props -->
|
||||
<PropertyGroup Label="Globals">
|
||||
<CppWinRTEnabled>true</CppWinRTEnabled>
|
||||
<CppWinRTOptimized>true</CppWinRTOptimized>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<MinimumVisualStudioVersion>17.0</MinimumVisualStudioVersion>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<MinimalCoreWin>true</MinimalCoreWin>
|
||||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<WindowsStoreApp>true</WindowsStoreApp>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<UseCrtSDKReference Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReference>
|
||||
<!-- The SDK reference breaks the Hybrid CRT -->
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<!-- We have to use the Desktop platform for Hybrid CRT to work. -->
|
||||
<_VC_Target_Library_Platform>Desktop</_VC_Target_Library_Platform>
|
||||
<_NoWinAPIFamilyApp>true</_NoWinAPIFamilyApp>
|
||||
</PropertyGroup>
|
||||
<!-- END cppwinrt.build.pre.props -->
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
</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>CmdPalKeyboardService</TargetName>
|
||||
<OutDir>..\..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
|
||||
<PreprocessorDefinitions>_WINRT_DLL;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../../../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
<ModuleDefinitionFile>CmdPalKeyboardService.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>Shell32.lib;user32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="KeyboardListener.h">
|
||||
<DependentUpon>KeyboardListener.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyboardListener.cpp">
|
||||
<DependentUpon>KeyboardListener.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="KeyboardListener.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="CmdPalKeyboardService.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="PropertySheet.props" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\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.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
<!-- BEGIN common.build.post.props -->
|
||||
<!--
|
||||
The Hybrid CRT model statically links the runtime and STL and dynamically
|
||||
links the UCRT instead of the VC++ CRT. The UCRT ships with Windows.
|
||||
WinAppSDK asserts that this is "supported according to the CRT maintainer."
|
||||
|
||||
This must come before Microsoft.Cpp.targets because it manipulates ClCompile.RuntimeLibrary.
|
||||
-->
|
||||
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and '$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and ('$(Configuration)'=='Release' or '$(Configuration)'=='AuditMode')">
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<!-- END common.build.post.props -->
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Resources">
|
||||
<UniqueIdentifier>accd3aa8-1ba0-4223-9bbe-0c431709210b</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{926ab91d-31b4-48c3-b9a4-e681349f27f0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="KeyboardListener.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CmdPalKeyboardService.def" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="PropertySheet.props" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
165
src/modules/Deux/UI/CmdPalKeyboardService/KeyboardListener.cpp
Normal file
165
src/modules/Deux/UI/CmdPalKeyboardService/KeyboardListener.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#include "pch.h"
|
||||
#include "KeyboardListener.h"
|
||||
#include "KeyboardListener.g.cpp"
|
||||
|
||||
// #include <common/logger/logger.h>
|
||||
// #include <common/utils/logger_helper.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
}
|
||||
|
||||
namespace winrt::CmdPalKeyboardService::implementation
|
||||
{
|
||||
KeyboardListener::KeyboardListener()
|
||||
{
|
||||
s_instance = this;
|
||||
}
|
||||
|
||||
void KeyboardListener::Start()
|
||||
{
|
||||
#if defined(DISABLE_LOWLEVEL_HOOKS_WHEN_DEBUGGED)
|
||||
const bool hook_disabled = IsDebuggerPresent();
|
||||
#else
|
||||
const bool hook_disabled = false;
|
||||
#endif
|
||||
if (!hook_disabled)
|
||||
{
|
||||
if (!s_llKeyboardHook)
|
||||
{
|
||||
s_llKeyboardHook = SetWindowsHookExW(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, NULL);
|
||||
if (!s_llKeyboardHook)
|
||||
{
|
||||
DWORD errorCode = GetLastError();
|
||||
show_last_error_message(L"SetWindowsHookEx", errorCode, L"CmdPalKeyboardService");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::Stop()
|
||||
{
|
||||
if (s_llKeyboardHook && UnhookWindowsHookEx(s_llKeyboardHook))
|
||||
{
|
||||
s_llKeyboardHook = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::SetHotkeyAction(bool win, bool ctrl, bool shift, bool alt, uint8_t key, hstring const& id)
|
||||
{
|
||||
Hotkey hotkey = { .win = win, .ctrl = ctrl, .shift = shift, .alt = alt, .key = key };
|
||||
std::unique_lock lock{ mutex };
|
||||
|
||||
HotkeyDescriptor desc = { .hotkey = hotkey, .id = std::wstring(id) };
|
||||
hotkeyDescriptors.insert(desc);
|
||||
}
|
||||
|
||||
void KeyboardListener::ClearHotkey(hstring const& id)
|
||||
{
|
||||
{
|
||||
std::unique_lock lock{ mutex };
|
||||
auto it = hotkeyDescriptors.begin();
|
||||
while (it != hotkeyDescriptors.end())
|
||||
{
|
||||
if (it->id == id)
|
||||
{
|
||||
it = hotkeyDescriptors.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::ClearHotkeys()
|
||||
{
|
||||
{
|
||||
std::unique_lock lock{ mutex };
|
||||
auto it = hotkeyDescriptors.begin();
|
||||
while (it != hotkeyDescriptors.end())
|
||||
{
|
||||
it = hotkeyDescriptors.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::SetProcessCommand(ProcessCommand processCommand)
|
||||
{
|
||||
m_processCommandCb = [trigger = std::move(processCommand)](hstring const& id) {
|
||||
trigger(id);
|
||||
};
|
||||
}
|
||||
|
||||
LRESULT KeyboardListener::DoLowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
const auto& keyPressInfo = *reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||
|
||||
if ((wParam != WM_KEYDOWN) && (wParam != WM_SYSKEYDOWN))
|
||||
{
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
Hotkey hotkey{
|
||||
.win = (GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000),
|
||||
.ctrl = static_cast<bool>(GetAsyncKeyState(VK_CONTROL) & 0x8000),
|
||||
.shift = static_cast<bool>(GetAsyncKeyState(VK_SHIFT) & 0x8000),
|
||||
.alt = static_cast<bool>(GetAsyncKeyState(VK_MENU) & 0x8000),
|
||||
.key = static_cast<unsigned char>(keyPressInfo.vkCode)
|
||||
};
|
||||
|
||||
if (hotkey == Hotkey{})
|
||||
{
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
bool do_action = false;
|
||||
std::wstring actionId{};
|
||||
|
||||
{
|
||||
// Hold the lock for the shortest possible duration
|
||||
std::unique_lock lock{ mutex };
|
||||
HotkeyDescriptor dummy{ .hotkey = hotkey };
|
||||
auto it = hotkeyDescriptors.find(dummy);
|
||||
if (it != hotkeyDescriptors.end())
|
||||
{
|
||||
do_action = true;
|
||||
actionId = it->id;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_action)
|
||||
{
|
||||
m_processCommandCb(hstring{ actionId });
|
||||
|
||||
// After invoking the hotkey send a dummy key to prevent Start Menu from activating
|
||||
INPUT dummyEvent[1] = {};
|
||||
dummyEvent[0].type = INPUT_KEYBOARD;
|
||||
dummyEvent[0].ki.wVk = 0xFF;
|
||||
dummyEvent[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
SendInput(1, dummyEvent, sizeof(INPUT));
|
||||
|
||||
// Swallow the key press
|
||||
return 1;
|
||||
}
|
||||
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT KeyboardListener::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (s_instance == nullptr)
|
||||
{
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
if (nCode < 0)
|
||||
{
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
return s_instance->DoLowLevelKeyboardProc(nCode, wParam, lParam);
|
||||
}
|
||||
}
|
||||
67
src/modules/Deux/UI/CmdPalKeyboardService/KeyboardListener.h
Normal file
67
src/modules/Deux/UI/CmdPalKeyboardService/KeyboardListener.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include "KeyboardListener.g.h"
|
||||
#include <mutex>
|
||||
#include <spdlog/stopwatch.h>
|
||||
#include <set>
|
||||
|
||||
namespace winrt::CmdPalKeyboardService::implementation
|
||||
{
|
||||
struct KeyboardListener : KeyboardListenerT<KeyboardListener>
|
||||
{
|
||||
struct Hotkey
|
||||
{
|
||||
bool win = false;
|
||||
bool ctrl = false;
|
||||
bool shift = false;
|
||||
bool alt = false;
|
||||
unsigned char key = 0;
|
||||
|
||||
std::strong_ordering operator<=>(const Hotkey&) const = default;
|
||||
};
|
||||
|
||||
struct HotkeyDescriptor
|
||||
{
|
||||
Hotkey hotkey;
|
||||
std::wstring id;
|
||||
|
||||
bool operator<(const HotkeyDescriptor& other) const
|
||||
{
|
||||
return hotkey < other.hotkey;
|
||||
};
|
||||
};
|
||||
|
||||
KeyboardListener();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
void SetHotkeyAction(bool win, bool ctrl, bool shift, bool alt, uint8_t key, hstring const& id);
|
||||
void ClearHotkey(hstring const& id);
|
||||
void ClearHotkeys();
|
||||
void SetProcessCommand(ProcessCommand processCommand);
|
||||
|
||||
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
LRESULT CALLBACK DoLowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
static inline KeyboardListener* s_instance;
|
||||
HHOOK s_llKeyboardHook = nullptr;
|
||||
|
||||
// Max DWORD for key code to disable keys.
|
||||
const DWORD VK_DISABLED = 0x100;
|
||||
DWORD vkCodePressed = VK_DISABLED;
|
||||
|
||||
std::multiset<HotkeyDescriptor> hotkeyDescriptors;
|
||||
std::mutex mutex;
|
||||
|
||||
std::function<void(hstring const&)> m_processCommandCb;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::CmdPalKeyboardService::factory_implementation
|
||||
{
|
||||
struct KeyboardListener : KeyboardListenerT<KeyboardListener, implementation::KeyboardListener>
|
||||
{
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
namespace CmdPalKeyboardService
|
||||
{
|
||||
[version(1.0), uuid(78ab07cd-e128-4e73-86aa-e48e6b6d01ff)] delegate void ProcessCommand(String id);
|
||||
|
||||
[default_interface] runtimeclass KeyboardListener {
|
||||
KeyboardListener();
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
void SetHotkeyAction(Boolean win, Boolean ctrl, Boolean shift, Boolean alt, UInt8 key, String id);
|
||||
void ClearHotkey(String id);
|
||||
void ClearHotkeys();
|
||||
void SetProcessCommand(ProcessCommand processCommand);
|
||||
}
|
||||
}
|
||||
453
src/modules/Deux/UI/CmdPalKeyboardService/KeyboardListener_h.h
Normal file
453
src/modules/Deux/UI/CmdPalKeyboardService/KeyboardListener_h.h
Normal file
@@ -0,0 +1,453 @@
|
||||
/* Header file automatically generated from KeyboardListener.idl */
|
||||
/*
|
||||
* File built with Microsoft(R) MIDLRT Compiler Engine Version 10.00.0231
|
||||
*/
|
||||
|
||||
#pragma warning( disable: 4049 ) /* more than 64k source lines */
|
||||
|
||||
/* verify that the <rpcndr.h> version is high enough to compile this file*/
|
||||
#ifndef __REQUIRED_RPCNDR_H_VERSION__
|
||||
#define __REQUIRED_RPCNDR_H_VERSION__ 500
|
||||
#endif
|
||||
|
||||
/* verify that the <rpcsal.h> version is high enough to compile this file*/
|
||||
#ifndef __REQUIRED_RPCSAL_H_VERSION__
|
||||
#define __REQUIRED_RPCSAL_H_VERSION__ 100
|
||||
#endif
|
||||
|
||||
#include <rpc.h>
|
||||
#include <rpcndr.h>
|
||||
|
||||
#ifndef __RPCNDR_H_VERSION__
|
||||
#error this stub requires an updated version of <rpcndr.h>
|
||||
#endif /* __RPCNDR_H_VERSION__ */
|
||||
|
||||
#ifndef COM_NO_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#include <ole2.h>
|
||||
#endif /*COM_NO_WINDOWS_H*/
|
||||
#ifndef __KeyboardListener_h_h__
|
||||
#define __KeyboardListener_h_h__
|
||||
#ifndef __KeyboardListener_h_p_h__
|
||||
#define __KeyboardListener_h_p_h__
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
// Ensure that the setting of the /ns_prefix command line switch is consistent for all headers.
|
||||
// If you get an error from the compiler indicating "warning C4005: 'CHECK_NS_PREFIX_STATE': macro redefinition", this
|
||||
// indicates that you have included two different headers with different settings for the /ns_prefix MIDL command line switch
|
||||
#if !defined(DISABLE_NS_PREFIX_CHECKS)
|
||||
#define CHECK_NS_PREFIX_STATE "always"
|
||||
#endif // !defined(DISABLE_NS_PREFIX_CHECKS)
|
||||
|
||||
|
||||
#pragma push_macro("MIDL_CONST_ID")
|
||||
#undef MIDL_CONST_ID
|
||||
#define MIDL_CONST_ID const __declspec(selectany)
|
||||
|
||||
|
||||
// Header files for imported files
|
||||
#include "winrtbase.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.AI.MachineLearning.MachineLearningContract\5.0.0.0\Windows.AI.MachineLearning.MachineLearningContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract\2.0.0.0\Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract\4.0.0.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.ApplicationModel.Calls.CallsPhoneContract\7.0.0.0\Windows.ApplicationModel.Calls.CallsPhoneContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.ApplicationModel.Calls.CallsVoipContract\5.0.0.0\Windows.ApplicationModel.Calls.CallsVoipContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract\2.0.0.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract\2.0.0.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.ApplicationModel.StartupTaskContract\3.0.0.0\Windows.ApplicationModel.StartupTaskContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Devices.Custom.CustomDeviceContract\1.0.0.0\Windows.Devices.Custom.CustomDeviceContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Devices.DevicesLowLevelContract\3.0.0.0\Windows.Devices.DevicesLowLevelContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Devices.Printers.PrintersContract\1.0.0.0\Windows.Devices.Printers.PrintersContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract\3.0.0.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Devices.SmartCards.SmartCardEmulatorContract\6.0.0.0\Windows.Devices.SmartCards.SmartCardEmulatorContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Foundation.FoundationContract\4.0.0.0\Windows.Foundation.FoundationContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Foundation.UniversalApiContract\19.0.0.0\Windows.Foundation.UniversalApiContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Gaming.XboxLive.StorageApiContract\1.0.0.0\Windows.Gaming.XboxLive.StorageApiContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Graphics.Printing3D.Printing3DContract\4.0.0.0\Windows.Graphics.Printing3D.Printing3DContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Networking.Connectivity.WwanContract\3.0.0.0\Windows.Networking.Connectivity.WwanContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Networking.Sockets.ControlChannelTriggerContract\3.0.0.0\Windows.Networking.Sockets.ControlChannelTriggerContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Security.Isolation.IsolatedWindowsEnvironmentContract\5.0.0.0\Windows.Security.Isolation.Isolatedwindowsenvironmentcontract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Services.Maps.GuidanceContract\3.0.0.0\Windows.Services.Maps.GuidanceContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Services.Maps.LocalSearchContract\4.0.0.0\Windows.Services.Maps.LocalSearchContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Services.Store.StoreContract\4.0.0.0\Windows.Services.Store.StoreContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Services.TargetedContent.TargetedContentContract\1.0.0.0\Windows.Services.TargetedContent.TargetedContentContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.Storage.Provider.CloudFilesContract\7.0.0.0\Windows.Storage.Provider.CloudFilesContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.System.Profile.ProfileHardwareTokenContract\1.0.0.0\Windows.System.Profile.ProfileHardwareTokenContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.System.Profile.ProfileRetailInfoContract\1.0.0.0\Windows.System.Profile.ProfileRetailInfoContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.System.Profile.ProfileSharedModeContract\2.0.0.0\Windows.System.Profile.ProfileSharedModeContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract\3.0.0.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.System.SystemManagementContract\7.0.0.0\Windows.System.SystemManagementContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.UI.UIAutomation.UIAutomationContract\2.0.0.0\Windows.UI.UIAutomation.UIAutomationContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract\1.0.0.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract.h"
|
||||
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0\Windows.UI.Xaml.Core.Direct.XamlDirectContract\5.0.0.0\Windows.UI.Xaml.Core.Direct.XamlDirectContract.h"
|
||||
|
||||
#if defined(__cplusplus) && !defined(CINTERFACE)
|
||||
#if defined(__MIDL_USE_C_ENUM)
|
||||
#define MIDL_ENUM enum
|
||||
#else
|
||||
#define MIDL_ENUM enum class
|
||||
#endif
|
||||
/* Forward Declarations */
|
||||
#ifndef ____x_ABI_CCmdPalKeyboardService_CIProcessCommand_FWD_DEFINED__
|
||||
#define ____x_ABI_CCmdPalKeyboardService_CIProcessCommand_FWD_DEFINED__
|
||||
namespace ABI {
|
||||
namespace CmdPalKeyboardService {
|
||||
interface IProcessCommand;
|
||||
} /* CmdPalKeyboardService */
|
||||
} /* ABI */
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIProcessCommand ABI::CmdPalKeyboardService::IProcessCommand
|
||||
|
||||
#endif // ____x_ABI_CCmdPalKeyboardService_CIProcessCommand_FWD_DEFINED__
|
||||
|
||||
#ifndef ____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_FWD_DEFINED__
|
||||
#define ____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_FWD_DEFINED__
|
||||
namespace ABI {
|
||||
namespace CmdPalKeyboardService {
|
||||
interface IKeyboardListener;
|
||||
} /* CmdPalKeyboardService */
|
||||
} /* ABI */
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener ABI::CmdPalKeyboardService::IKeyboardListener
|
||||
|
||||
#endif // ____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_FWD_DEFINED__
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Delegate CmdPalKeyboardService.ProcessCommand
|
||||
*
|
||||
*/
|
||||
#if !defined(____x_ABI_CCmdPalKeyboardService_CIProcessCommand_INTERFACE_DEFINED__)
|
||||
#define ____x_ABI_CCmdPalKeyboardService_CIProcessCommand_INTERFACE_DEFINED__
|
||||
namespace ABI {
|
||||
namespace CmdPalKeyboardService {
|
||||
/* [object, uuid("78ab07cd-e128-4e73-86aa-e48e6b6d01ff"), version] */
|
||||
MIDL_INTERFACE("78ab07cd-e128-4e73-86aa-e48e6b6d01ff")
|
||||
IProcessCommand : public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE Invoke(
|
||||
/* [in] */HSTRING id
|
||||
) = 0;
|
||||
|
||||
};
|
||||
|
||||
MIDL_CONST_ID IID & IID_IProcessCommand=__uuidof(IProcessCommand);
|
||||
|
||||
} /* CmdPalKeyboardService */
|
||||
} /* ABI */
|
||||
|
||||
EXTERN_C const IID IID___x_ABI_CCmdPalKeyboardService_CIProcessCommand;
|
||||
#endif /* !defined(____x_ABI_CCmdPalKeyboardService_CIProcessCommand_INTERFACE_DEFINED__) */
|
||||
|
||||
namespace ABI {
|
||||
namespace CmdPalKeyboardService {
|
||||
class KeyboardListener;
|
||||
} /* CmdPalKeyboardService */
|
||||
} /* ABI */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Interface CmdPalKeyboardService.IKeyboardListener
|
||||
*
|
||||
* Interface is a part of the implementation of type CmdPalKeyboardService.KeyboardListener
|
||||
*
|
||||
*
|
||||
* The IID for this interface was automatically generated by MIDLRT.
|
||||
*
|
||||
* Interface IID generation seed: CmdPalKeyboardService.IKeyboardListener:HRESULT Start();HRESULT Stop();HRESULT SetHotkeyAction(Boolean,Boolean,Boolean,Boolean,UInt8,String);HRESULT ClearHotkey(String);HRESULT ClearHotkeys();HRESULT SetProcessCommand(CmdPalKeyboardService.ProcessCommand*);
|
||||
*
|
||||
*
|
||||
*/
|
||||
#if !defined(____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_INTERFACE_DEFINED__)
|
||||
#define ____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_INTERFACE_DEFINED__
|
||||
extern const __declspec(selectany) _Null_terminated_ WCHAR InterfaceName_CmdPalKeyboardService_IKeyboardListener[] = L"CmdPalKeyboardService.IKeyboardListener";
|
||||
namespace ABI {
|
||||
namespace CmdPalKeyboardService {
|
||||
/* [uuid("2ae4bb1c-96bd-5c41-a41b-f25b9523efe9"), version, object, exclusiveto] */
|
||||
MIDL_INTERFACE("2ae4bb1c-96bd-5c41-a41b-f25b9523efe9")
|
||||
IKeyboardListener : public IInspectable
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE Start(void) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE Stop(void) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE SetHotkeyAction(
|
||||
/* [in] */::boolean win,
|
||||
/* [in] */::boolean ctrl,
|
||||
/* [in] */::boolean shift,
|
||||
/* [in] */::boolean alt,
|
||||
/* [in] */::byte key,
|
||||
/* [in] */HSTRING id
|
||||
) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE ClearHotkey(
|
||||
/* [in] */HSTRING id
|
||||
) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE ClearHotkeys(void) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE SetProcessCommand(
|
||||
/* [in] */ABI::CmdPalKeyboardService::IProcessCommand * processCommand
|
||||
) = 0;
|
||||
|
||||
};
|
||||
|
||||
MIDL_CONST_ID IID & IID_IKeyboardListener=__uuidof(IKeyboardListener);
|
||||
|
||||
} /* CmdPalKeyboardService */
|
||||
} /* ABI */
|
||||
|
||||
EXTERN_C const IID IID___x_ABI_CCmdPalKeyboardService_CIKeyboardListener;
|
||||
#endif /* !defined(____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_INTERFACE_DEFINED__) */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Class CmdPalKeyboardService.KeyboardListener
|
||||
*
|
||||
* RuntimeClass can be activated.
|
||||
*
|
||||
* Class implements the following interfaces:
|
||||
* CmdPalKeyboardService.IKeyboardListener ** Default Interface **
|
||||
*
|
||||
* Class Threading Model: Both Single and Multi Threaded Apartment
|
||||
*
|
||||
* Class Marshaling Behavior: Agile - Class is agile
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RUNTIMECLASS_CmdPalKeyboardService_KeyboardListener_DEFINED
|
||||
#define RUNTIMECLASS_CmdPalKeyboardService_KeyboardListener_DEFINED
|
||||
extern const __declspec(selectany) _Null_terminated_ WCHAR RuntimeClass_CmdPalKeyboardService_KeyboardListener[] = L"CmdPalKeyboardService.KeyboardListener";
|
||||
#endif
|
||||
|
||||
|
||||
#else // !defined(__cplusplus)
|
||||
/* Forward Declarations */
|
||||
#ifndef ____x_ABI_CCmdPalKeyboardService_CIProcessCommand_FWD_DEFINED__
|
||||
#define ____x_ABI_CCmdPalKeyboardService_CIProcessCommand_FWD_DEFINED__
|
||||
typedef interface __x_ABI_CCmdPalKeyboardService_CIProcessCommand __x_ABI_CCmdPalKeyboardService_CIProcessCommand;
|
||||
|
||||
#endif // ____x_ABI_CCmdPalKeyboardService_CIProcessCommand_FWD_DEFINED__
|
||||
|
||||
#ifndef ____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_FWD_DEFINED__
|
||||
#define ____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_FWD_DEFINED__
|
||||
typedef interface __x_ABI_CCmdPalKeyboardService_CIKeyboardListener __x_ABI_CCmdPalKeyboardService_CIKeyboardListener;
|
||||
|
||||
#endif // ____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_FWD_DEFINED__
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Delegate CmdPalKeyboardService.ProcessCommand
|
||||
*
|
||||
*/
|
||||
#if !defined(____x_ABI_CCmdPalKeyboardService_CIProcessCommand_INTERFACE_DEFINED__)
|
||||
#define ____x_ABI_CCmdPalKeyboardService_CIProcessCommand_INTERFACE_DEFINED__
|
||||
/* [object, uuid("78ab07cd-e128-4e73-86aa-e48e6b6d01ff"), version] */
|
||||
typedef struct __x_ABI_CCmdPalKeyboardService_CIProcessCommandVtbl
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
|
||||
__RPC__in __x_ABI_CCmdPalKeyboardService_CIProcessCommand * This,
|
||||
/* [in] */ __RPC__in REFIID riid,
|
||||
/* [annotation][iid_is][out] */
|
||||
_COM_Outptr_ void **ppvObject);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *AddRef )(
|
||||
__RPC__in __x_ABI_CCmdPalKeyboardService_CIProcessCommand * This);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *Release )(
|
||||
__RPC__in __x_ABI_CCmdPalKeyboardService_CIProcessCommand * This);
|
||||
HRESULT ( STDMETHODCALLTYPE *Invoke )(
|
||||
__x_ABI_CCmdPalKeyboardService_CIProcessCommand * This,
|
||||
/* [in] */HSTRING id
|
||||
);
|
||||
END_INTERFACE
|
||||
|
||||
} __x_ABI_CCmdPalKeyboardService_CIProcessCommandVtbl;
|
||||
|
||||
interface __x_ABI_CCmdPalKeyboardService_CIProcessCommand
|
||||
{
|
||||
CONST_VTBL struct __x_ABI_CCmdPalKeyboardService_CIProcessCommandVtbl *lpVtbl;
|
||||
};
|
||||
|
||||
#ifdef COBJMACROS
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIProcessCommand_QueryInterface(This,riid,ppvObject) \
|
||||
( (This)->lpVtbl->QueryInterface(This,riid,ppvObject) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIProcessCommand_AddRef(This) \
|
||||
( (This)->lpVtbl->AddRef(This) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIProcessCommand_Release(This) \
|
||||
( (This)->lpVtbl->Release(This) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIProcessCommand_Invoke(This,id) \
|
||||
( (This)->lpVtbl->Invoke(This,id) )
|
||||
|
||||
|
||||
#endif /* COBJMACROS */
|
||||
|
||||
|
||||
EXTERN_C const IID IID___x_ABI_CCmdPalKeyboardService_CIProcessCommand;
|
||||
#endif /* !defined(____x_ABI_CCmdPalKeyboardService_CIProcessCommand_INTERFACE_DEFINED__) */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Interface CmdPalKeyboardService.IKeyboardListener
|
||||
*
|
||||
* Interface is a part of the implementation of type CmdPalKeyboardService.KeyboardListener
|
||||
*
|
||||
*
|
||||
* The IID for this interface was automatically generated by MIDLRT.
|
||||
*
|
||||
* Interface IID generation seed: CmdPalKeyboardService.IKeyboardListener:HRESULT Start();HRESULT Stop();HRESULT SetHotkeyAction(Boolean,Boolean,Boolean,Boolean,UInt8,String);HRESULT ClearHotkey(String);HRESULT ClearHotkeys();HRESULT SetProcessCommand(CmdPalKeyboardService.ProcessCommand*);
|
||||
*
|
||||
*
|
||||
*/
|
||||
#if !defined(____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_INTERFACE_DEFINED__)
|
||||
#define ____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_INTERFACE_DEFINED__
|
||||
extern const __declspec(selectany) _Null_terminated_ WCHAR InterfaceName_CmdPalKeyboardService_IKeyboardListener[] = L"CmdPalKeyboardService.IKeyboardListener";
|
||||
/* [uuid("2ae4bb1c-96bd-5c41-a41b-f25b9523efe9"), version, object, exclusiveto] */
|
||||
typedef struct __x_ABI_CCmdPalKeyboardService_CIKeyboardListenerVtbl
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
HRESULT ( STDMETHODCALLTYPE *QueryInterface)(
|
||||
__RPC__in __x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This,
|
||||
/* [in] */ __RPC__in REFIID riid,
|
||||
/* [annotation][iid_is][out] */
|
||||
_COM_Outptr_ void **ppvObject
|
||||
);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *AddRef )(
|
||||
__RPC__in __x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This
|
||||
);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *Release )(
|
||||
__RPC__in __x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This
|
||||
);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *GetIids )(
|
||||
__RPC__in __x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This,
|
||||
/* [out] */ __RPC__out ULONG *iidCount,
|
||||
/* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*iidCount) IID **iids
|
||||
);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *GetRuntimeClassName )(
|
||||
__RPC__in __x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This,
|
||||
/* [out] */ __RPC__deref_out_opt HSTRING *className
|
||||
);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *GetTrustLevel )(
|
||||
__RPC__in __x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This,
|
||||
/* [OUT ] */ __RPC__out TrustLevel *trustLevel
|
||||
);
|
||||
HRESULT ( STDMETHODCALLTYPE *Start )(
|
||||
__x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This
|
||||
);
|
||||
HRESULT ( STDMETHODCALLTYPE *Stop )(
|
||||
__x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This
|
||||
);
|
||||
HRESULT ( STDMETHODCALLTYPE *SetHotkeyAction )(
|
||||
__x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This,
|
||||
/* [in] */boolean win,
|
||||
/* [in] */boolean ctrl,
|
||||
/* [in] */boolean shift,
|
||||
/* [in] */boolean alt,
|
||||
/* [in] */byte key,
|
||||
/* [in] */HSTRING id
|
||||
);
|
||||
HRESULT ( STDMETHODCALLTYPE *ClearHotkey )(
|
||||
__x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This,
|
||||
/* [in] */HSTRING id
|
||||
);
|
||||
HRESULT ( STDMETHODCALLTYPE *ClearHotkeys )(
|
||||
__x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This
|
||||
);
|
||||
HRESULT ( STDMETHODCALLTYPE *SetProcessCommand )(
|
||||
__x_ABI_CCmdPalKeyboardService_CIKeyboardListener * This,
|
||||
/* [in] */__x_ABI_CCmdPalKeyboardService_CIProcessCommand * processCommand
|
||||
);
|
||||
END_INTERFACE
|
||||
|
||||
} __x_ABI_CCmdPalKeyboardService_CIKeyboardListenerVtbl;
|
||||
|
||||
interface __x_ABI_CCmdPalKeyboardService_CIKeyboardListener
|
||||
{
|
||||
CONST_VTBL struct __x_ABI_CCmdPalKeyboardService_CIKeyboardListenerVtbl *lpVtbl;
|
||||
};
|
||||
|
||||
#ifdef COBJMACROS
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_QueryInterface(This,riid,ppvObject) \
|
||||
( (This)->lpVtbl->QueryInterface(This,riid,ppvObject) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_AddRef(This) \
|
||||
( (This)->lpVtbl->AddRef(This) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_Release(This) \
|
||||
( (This)->lpVtbl->Release(This) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_GetIids(This,iidCount,iids) \
|
||||
( (This)->lpVtbl->GetIids(This,iidCount,iids) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_GetRuntimeClassName(This,className) \
|
||||
( (This)->lpVtbl->GetRuntimeClassName(This,className) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_GetTrustLevel(This,trustLevel) \
|
||||
( (This)->lpVtbl->GetTrustLevel(This,trustLevel) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_Start(This) \
|
||||
( (This)->lpVtbl->Start(This) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_Stop(This) \
|
||||
( (This)->lpVtbl->Stop(This) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_SetHotkeyAction(This,win,ctrl,shift,alt,key,id) \
|
||||
( (This)->lpVtbl->SetHotkeyAction(This,win,ctrl,shift,alt,key,id) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_ClearHotkey(This,id) \
|
||||
( (This)->lpVtbl->ClearHotkey(This,id) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_ClearHotkeys(This) \
|
||||
( (This)->lpVtbl->ClearHotkeys(This) )
|
||||
|
||||
#define __x_ABI_CCmdPalKeyboardService_CIKeyboardListener_SetProcessCommand(This,processCommand) \
|
||||
( (This)->lpVtbl->SetProcessCommand(This,processCommand) )
|
||||
|
||||
|
||||
#endif /* COBJMACROS */
|
||||
|
||||
|
||||
EXTERN_C const IID IID___x_ABI_CCmdPalKeyboardService_CIKeyboardListener;
|
||||
#endif /* !defined(____x_ABI_CCmdPalKeyboardService_CIKeyboardListener_INTERFACE_DEFINED__) */
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Class CmdPalKeyboardService.KeyboardListener
|
||||
*
|
||||
* RuntimeClass can be activated.
|
||||
*
|
||||
* Class implements the following interfaces:
|
||||
* CmdPalKeyboardService.IKeyboardListener ** Default Interface **
|
||||
*
|
||||
* Class Threading Model: Both Single and Multi Threaded Apartment
|
||||
*
|
||||
* Class Marshaling Behavior: Agile - Class is agile
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RUNTIMECLASS_CmdPalKeyboardService_KeyboardListener_DEFINED
|
||||
#define RUNTIMECLASS_CmdPalKeyboardService_KeyboardListener_DEFINED
|
||||
extern const __declspec(selectany) _Null_terminated_ WCHAR RuntimeClass_CmdPalKeyboardService_KeyboardListener[] = L"CmdPalKeyboardService.KeyboardListener";
|
||||
#endif
|
||||
|
||||
|
||||
#endif // defined(__cplusplus)
|
||||
#pragma pop_macro("MIDL_CONST_ID")
|
||||
#endif // __KeyboardListener_h_p_h__
|
||||
|
||||
#endif // __KeyboardListener_h_h__
|
||||
@@ -0,0 +1,17 @@
|
||||
<?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>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
</packages>
|
||||
1
src/modules/Deux/UI/CmdPalKeyboardService/pch.cpp
Normal file
1
src/modules/Deux/UI/CmdPalKeyboardService/pch.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
4
src/modules/Deux/UI/CmdPalKeyboardService/pch.h
Normal file
4
src/modules/Deux/UI/CmdPalKeyboardService/pch.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <Unknwn.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Models;
|
||||
|
||||
public class CommandHotKey(Hotkey? hotkey, string commandId)
|
||||
{
|
||||
public string CommandId { get; set; } = commandId;
|
||||
|
||||
public Hotkey? Hotkey { get; set; } = hotkey;
|
||||
}
|
||||
@@ -9,11 +9,11 @@ using Microsoft.CommandPalette.UI.Models.Helpers;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Models;
|
||||
|
||||
public record HotkeySettings
|
||||
public record Hotkey
|
||||
{
|
||||
private const int VKTAB = 0x09;
|
||||
|
||||
public HotkeySettings()
|
||||
public Hotkey()
|
||||
{
|
||||
Win = false;
|
||||
Ctrl = false;
|
||||
@@ -23,14 +23,14 @@ public record HotkeySettings
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HotkeySettings"/> class.
|
||||
/// Initializes a new instance of the <see cref="Hotkey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="win">Should Windows key be used</param>
|
||||
/// <param name="ctrl">Should Ctrl key be used</param>
|
||||
/// <param name="alt">Should Alt key be used</param>
|
||||
/// <param name="shift">Should Shift key be used</param>
|
||||
/// <param name="code">Go to https://learn.microsoft.com/windows/win32/inputdev/virtual-key-codes to see list of v-keys</param>
|
||||
public HotkeySettings(bool win, bool ctrl, bool alt, bool shift, int code)
|
||||
public Hotkey(bool win, bool ctrl, bool alt, bool shift, int code)
|
||||
{
|
||||
Win = win;
|
||||
Ctrl = ctrl;
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Windows.System;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Models;
|
||||
|
||||
public class KeyPressedEventArgs(VirtualKey key) : EventArgs
|
||||
{
|
||||
public VirtualKey Key { get; } = key;
|
||||
}
|
||||
@@ -11,9 +11,9 @@ public partial class SettingsModel
|
||||
* Make sure that any new types you add are added to JsonSerializationContext!
|
||||
*************************************************************************/
|
||||
|
||||
public static HotkeySettings DefaultActivationShortcut { get; } = new HotkeySettings(true, false, true, false, 0x20); // win+alt+space
|
||||
public static Hotkey DefaultActivationShortcut { get; } = new Hotkey(true, false, true, false, 0x20); // win+alt+space
|
||||
|
||||
public HotkeySettings? Hotkey { get; set; } = DefaultActivationShortcut;
|
||||
public Hotkey? Hotkey { get; set; } = DefaultActivationShortcut;
|
||||
|
||||
public bool UseLowLevelGlobalHotkey { get; set; }
|
||||
|
||||
@@ -40,4 +40,6 @@ public partial class SettingsModel
|
||||
public WindowPosition? LastWindowPosition { get; set; }
|
||||
|
||||
public TimeSpan AutoGoHomeInterval { get; set; } = Timeout.InfiniteTimeSpan;
|
||||
|
||||
public List<CommandHotKey> CommandHotkeys { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -6,5 +6,4 @@ namespace Microsoft.CommandPalette.UI.Services.Extensions;
|
||||
|
||||
public interface IExtensionService
|
||||
{
|
||||
CommandViewModel
|
||||
}
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
// 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 CmdPalKeyboardService;
|
||||
using Microsoft.CommandPalette.UI.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Windows.System;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.Input.KeyboardAndMouse;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Services;
|
||||
|
||||
public partial class KeyboardService : IDisposable
|
||||
{
|
||||
private readonly KeyboardListener _keyboardListener;
|
||||
private readonly SettingsService _settingsService;
|
||||
private readonly ILogger _logger;
|
||||
private readonly List<CommandHotKey> _hotkeys = [];
|
||||
|
||||
private HWND _hwnd;
|
||||
private bool _disposed;
|
||||
private UnhookWindowsHookExSafeHandle? _handle;
|
||||
private HOOKPROC? _hookProc; // Keep reference to prevent GC collection
|
||||
|
||||
/// <summary>
|
||||
/// Event that is raised when a key is pressed down.
|
||||
/// </summary>
|
||||
public event EventHandler<KeyPressedEventArgs>? KeyPressed;
|
||||
|
||||
public KeyboardService(SettingsService settingsService, ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_settingsService = settingsService;
|
||||
_keyboardListener = new KeyboardListener();
|
||||
_keyboardListener.Start();
|
||||
|
||||
StartListening();
|
||||
|
||||
_settingsService.SettingsChanged += SettingsChanged;
|
||||
}
|
||||
|
||||
public void SetProcessCommand(HWND hwnd, ProcessCommand processCommand)
|
||||
{
|
||||
_hwnd = hwnd;
|
||||
_keyboardListener.SetProcessCommand(processCommand);
|
||||
SetupHotkeys();
|
||||
}
|
||||
|
||||
private void SettingsChanged(SettingsModel sender, object? e)
|
||||
{
|
||||
SetupHotkeys();
|
||||
}
|
||||
|
||||
private void UnregisterHotkeys()
|
||||
{
|
||||
_keyboardListener.ClearHotkeys();
|
||||
|
||||
while (_hotkeys.Count > 0)
|
||||
{
|
||||
PInvoke.UnregisterHotKey(_hwnd, _hotkeys.Count - 1);
|
||||
_hotkeys.RemoveAt(_hotkeys.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupHotkeys()
|
||||
{
|
||||
UnregisterHotkeys();
|
||||
|
||||
var globalHotkey = _settingsService.CurrentSettings.Hotkey;
|
||||
if (globalHotkey is not null)
|
||||
{
|
||||
if (_settingsService.CurrentSettings.UseLowLevelGlobalHotkey)
|
||||
{
|
||||
_keyboardListener.SetHotkeyAction(globalHotkey.Win, globalHotkey.Ctrl, globalHotkey.Shift, globalHotkey.Alt, (byte)globalHotkey.Code, string.Empty);
|
||||
_hotkeys.Add(new(globalHotkey, string.Empty));
|
||||
}
|
||||
else
|
||||
{
|
||||
var vk = globalHotkey.Code;
|
||||
var modifiers =
|
||||
(globalHotkey.Alt ? HOT_KEY_MODIFIERS.MOD_ALT : 0) |
|
||||
(globalHotkey.Ctrl ? HOT_KEY_MODIFIERS.MOD_CONTROL : 0) |
|
||||
(globalHotkey.Shift ? HOT_KEY_MODIFIERS.MOD_SHIFT : 0) |
|
||||
(globalHotkey.Win ? HOT_KEY_MODIFIERS.MOD_WIN : 0)
|
||||
;
|
||||
|
||||
var success = PInvoke.RegisterHotKey(_hwnd, _hotkeys.Count, modifiers, (uint)vk);
|
||||
if (success)
|
||||
{
|
||||
_hotkeys.Add(new(globalHotkey, string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var commandHotkey in _settingsService.CurrentSettings.CommandHotkeys)
|
||||
{
|
||||
var key = commandHotkey.Hotkey;
|
||||
if (key is not null)
|
||||
{
|
||||
if (_settingsService.CurrentSettings.UseLowLevelGlobalHotkey)
|
||||
{
|
||||
_keyboardListener.SetHotkeyAction(key.Win, key.Ctrl, key.Shift, key.Alt, (byte)key.Code, commandHotkey.CommandId);
|
||||
_hotkeys.Add(new(commandHotkey.Hotkey, commandHotkey.CommandId));
|
||||
}
|
||||
else
|
||||
{
|
||||
var vk = key.Code;
|
||||
var modifiers =
|
||||
(key.Alt ? HOT_KEY_MODIFIERS.MOD_ALT : 0) |
|
||||
(key.Ctrl ? HOT_KEY_MODIFIERS.MOD_CONTROL : 0) |
|
||||
(key.Shift ? HOT_KEY_MODIFIERS.MOD_SHIFT : 0) |
|
||||
(key.Win ? HOT_KEY_MODIFIERS.MOD_WIN : 0)
|
||||
;
|
||||
var success = PInvoke.RegisterHotKey(_hwnd, _hotkeys.Count, modifiers, (uint)vk);
|
||||
if (success)
|
||||
{
|
||||
_hotkeys.Add(commandHotkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool StartListening()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
RegisterKeyboardHook();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log_FailedToRegisterHook(ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterKeyboardHook()
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (_handle is not null && !_handle.IsInvalid)
|
||||
{
|
||||
// Hook is already set
|
||||
return;
|
||||
}
|
||||
|
||||
_hookProc = KeyEventHook;
|
||||
if (!SetWindowKeyHook(_hookProc))
|
||||
{
|
||||
throw new InvalidOperationException("Failed to register keyboard hook.");
|
||||
}
|
||||
}
|
||||
|
||||
private bool SetWindowKeyHook(HOOKPROC hookProc)
|
||||
{
|
||||
if (_handle is not null && !_handle.IsInvalid)
|
||||
{
|
||||
// Hook is already set
|
||||
return false;
|
||||
}
|
||||
|
||||
_handle = PInvoke.SetWindowsHookEx(
|
||||
WINDOWS_HOOK_ID.WH_KEYBOARD,
|
||||
hookProc,
|
||||
PInvoke.GetModuleHandle(null),
|
||||
PInvoke.GetCurrentThreadId());
|
||||
|
||||
// Check if the hook was successfully set
|
||||
return _handle is not null && !_handle.IsInvalid;
|
||||
}
|
||||
|
||||
private static bool IsKeyDownHook(LPARAM lParam)
|
||||
{
|
||||
// The 30th bit tells what the previous key state is with 0 being the "UP" state
|
||||
// For more info see https://learn.microsoft.com/windows/win32/winmsg/keyboardproc#lparam-in
|
||||
return ((lParam.Value >> 30) & 1) == 0;
|
||||
}
|
||||
|
||||
private LRESULT KeyEventHook(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (nCode >= 0 && IsKeyDownHook(lParam))
|
||||
{
|
||||
InvokeKeyDown((VirtualKey)wParam.Value);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log_ErrorInvokingKeyDownHook(ex);
|
||||
}
|
||||
|
||||
// Call next hook in chain - pass null as first parameter for current hook
|
||||
return PInvoke.CallNextHookEx(null, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
private void InvokeKeyDown(VirtualKey virtualKey)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
KeyPressed?.Invoke(this, new KeyPressedEventArgs(virtualKey));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UnregisterHotkeys();
|
||||
|
||||
if (_settingsService is not null)
|
||||
{
|
||||
_settingsService.SettingsChanged -= SettingsChanged;
|
||||
}
|
||||
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void UnregisterKeyboardHook()
|
||||
{
|
||||
if (_handle is not null && !_handle.IsInvalid)
|
||||
{
|
||||
// The SafeHandle should automatically call UnhookWindowsHookEx when disposed
|
||||
_handle.Dispose();
|
||||
_handle = null;
|
||||
}
|
||||
|
||||
_hookProc = null;
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
UnregisterKeyboardHook();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "Failed to register hook")]
|
||||
partial void Log_FailedToRegisterHook(Exception ex);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "Failed when invoking key down keyboard hook event")]
|
||||
partial void Log_ErrorInvokingKeyDownHook(Exception ex);
|
||||
}
|
||||
@@ -26,10 +26,22 @@
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- This lets us actually reference types from Microsoft.Terminal.UI -->
|
||||
<CsWinRTIncludes>Microsoft.Terminal.UI;CmdPalKeyboardService</CsWinRTIncludes>
|
||||
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\SDK\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.CommandPalette.UI.Models\Microsoft.CommandPalette.UI.Models.csproj" />
|
||||
|
||||
<ProjectReference Include="..\CmdPalKeyboardService\CmdPalKeyboardService.vcxproj">
|
||||
<ReferenceOutputAssembly>True</ReferenceOutputAssembly>
|
||||
<Private>True</Private>
|
||||
<CopyLocalSatelliteAssemblies>True</CopyLocalSatelliteAssemblies>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -80,6 +80,7 @@ public partial class App : Application
|
||||
services.AddSingleton<IExtensionService, JsonRPCExtensionService>();
|
||||
|
||||
// Register services
|
||||
services.AddSingleton<KeyboardService>();
|
||||
services.AddSingleton<TrayIconService>();
|
||||
|
||||
// Register view models
|
||||
|
||||
@@ -32,7 +32,6 @@ using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Dwm;
|
||||
using Windows.Win32.Graphics.Gdi;
|
||||
using Windows.Win32.UI.HiDpi;
|
||||
using Windows.Win32.UI.Input.KeyboardAndMouse;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using WinRT;
|
||||
using WinUIEx;
|
||||
@@ -50,6 +49,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
private readonly ShellPage _shellPage;
|
||||
private readonly SettingsService _settingsService;
|
||||
private readonly TrayIconService _trayIconService;
|
||||
private readonly KeyboardService _keyboardService;
|
||||
private const int DefaultWidth = 800;
|
||||
private const int DefaultHeight = 480;
|
||||
|
||||
@@ -61,9 +61,6 @@ public sealed partial class MainWindow : WindowEx,
|
||||
private readonly WNDPROC? _hotkeyWndProc;
|
||||
private readonly WNDPROC? _originalWndProc;
|
||||
|
||||
// private readonly List<TopLevelHotkey> _hotkeys = [];
|
||||
// private readonly KeyboardListener _keyboardListener;
|
||||
// private readonly LocalKeyboardListener _localKeyboardListener;
|
||||
private readonly HiddenOwnerWindowBehavior _hiddenOwnerBehavior = new();
|
||||
private bool _ignoreHotKeyWhenFullScreen = true;
|
||||
|
||||
@@ -73,7 +70,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
private WindowPosition _currentWindowPosition = new();
|
||||
|
||||
public MainWindow(ShellPage shellPage, SettingsService settingsService, TrayIconService trayIconService, ILogger logger)
|
||||
public MainWindow(ShellPage shellPage, SettingsService settingsService, TrayIconService trayIconService, KeyboardService keyboardService, ILogger logger)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
@@ -81,6 +78,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
_shellPage = shellPage;
|
||||
_settingsService = settingsService;
|
||||
_trayIconService = trayIconService;
|
||||
_keyboardService = keyboardService;
|
||||
|
||||
RootElement.Children.Add(_shellPage);
|
||||
|
||||
@@ -95,9 +93,9 @@ public sealed partial class MainWindow : WindowEx,
|
||||
// }
|
||||
_hiddenOwnerBehavior.ShowInTaskbar(this, Debugger.IsAttached);
|
||||
|
||||
// _keyboardListener = new KeyboardListener();
|
||||
// _keyboardListener.Start();
|
||||
// _keyboardListener.SetProcessCommand(new CmdPalKeyboardService.ProcessCommand(HandleSummon));
|
||||
_keyboardService.KeyPressed += KeyboardService_OnKeyPressed;
|
||||
_keyboardService.SetProcessCommand(_hwnd, new CmdPalKeyboardService.ProcessCommand(HandleSummon));
|
||||
|
||||
this.SetIcon();
|
||||
AppWindow.Title = RS_.GetString("AppName");
|
||||
RestoreWindowPosition();
|
||||
@@ -143,13 +141,18 @@ public sealed partial class MainWindow : WindowEx,
|
||||
Summon(string.Empty);
|
||||
});
|
||||
|
||||
// _localKeyboardListener = new LocalKeyboardListener();
|
||||
// _localKeyboardListener.KeyPressed += LocalKeyboardListener_OnKeyPressed;
|
||||
// _localKeyboardListener.Start();
|
||||
// Force window to be created, and then cloaked. This will offset initial animation when the window is shown.
|
||||
HideWindow();
|
||||
}
|
||||
|
||||
private void KeyboardService_OnKeyPressed(object? sender, KeyPressedEventArgs e)
|
||||
{
|
||||
if (e.Key == VirtualKey.GoBack)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new GoBackMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(ShowWindowMessage message)
|
||||
{
|
||||
ShowHwnd(message.Hwnd, _settingsService.CurrentSettings.SummonOn);
|
||||
@@ -187,7 +190,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
WeakReferenceMessenger.Default.Send(new GoHomeMessage(WithAnimation: false, FocusSearch: false));
|
||||
}
|
||||
|
||||
private static void LocalKeyboardListener_OnKeyPressed(object? sender, LocalKeyboardListenerKeyPressedEventArgs e)
|
||||
private static void KeyboardService_OnKeyPressed(object? sender, LocalKeyboardListenerKeyPressedEventArgs e)
|
||||
{
|
||||
if (e.Key == VirtualKey.GoBack)
|
||||
{
|
||||
@@ -266,8 +269,6 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
private void HotReloadSettings()
|
||||
{
|
||||
SetupHotkey(_settingsService.CurrentSettings);
|
||||
|
||||
_ignoreHotKeyWhenFullScreen = _settingsService.CurrentSettings.IgnoreShortcutWhenFullscreen;
|
||||
|
||||
_autoGoHomeInterval = _settingsService.CurrentSettings.AutoGoHomeInterval;
|
||||
@@ -634,13 +635,13 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
// var extensionService = serviceProvider.GetService<IExtensionService>()!;
|
||||
// extensionService.SignalStopExtensionsAsync();
|
||||
// _trayIconService.Destroy();
|
||||
_trayIconService.Destroy();
|
||||
|
||||
// WinUI bug is causing a crash on shutdown when FailFastOnErrors is set to true (#51773592).
|
||||
// Workaround by turning it off before shutdown.
|
||||
App.Current.DebugSettings.FailFastOnErrors = false;
|
||||
|
||||
// _localKeyboardListener.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
DisposeAcrylic();
|
||||
|
||||
// _keyboardListener.Stop();
|
||||
@@ -817,76 +818,6 @@ public sealed partial class MainWindow : WindowEx,
|
||||
// know till the message is being handled.
|
||||
WeakReferenceMessenger.Default.Send<HotkeySummonMessage>(new(commandId, _hwnd));
|
||||
|
||||
private void UnregisterHotkeys()
|
||||
{
|
||||
// _keyboardListener.ClearHotkeys();
|
||||
|
||||
// while (_hotkeys.Count > 0)
|
||||
// {
|
||||
// PInvoke.UnregisterHotKey(_hwnd, _hotkeys.Count - 1);
|
||||
// _hotkeys.RemoveAt(_hotkeys.Count - 1);
|
||||
// }
|
||||
}
|
||||
|
||||
private void SetupHotkey(SettingsModel settings)
|
||||
{
|
||||
UnregisterHotkeys();
|
||||
|
||||
var globalHotkey = settings.Hotkey;
|
||||
if (globalHotkey is not null)
|
||||
{
|
||||
if (settings.UseLowLevelGlobalHotkey)
|
||||
{
|
||||
// _keyboardListener.SetHotkeyAction(globalHotkey.Win, globalHotkey.Ctrl, globalHotkey.Shift, globalHotkey.Alt, (byte)globalHotkey.Code, string.Empty);
|
||||
// _hotkeys.Add(new(globalHotkey, string.Empty));
|
||||
}
|
||||
else
|
||||
{
|
||||
var vk = globalHotkey.Code;
|
||||
var modifiers =
|
||||
(globalHotkey.Alt ? HOT_KEY_MODIFIERS.MOD_ALT : 0) |
|
||||
(globalHotkey.Ctrl ? HOT_KEY_MODIFIERS.MOD_CONTROL : 0) |
|
||||
(globalHotkey.Shift ? HOT_KEY_MODIFIERS.MOD_SHIFT : 0) |
|
||||
(globalHotkey.Win ? HOT_KEY_MODIFIERS.MOD_WIN : 0)
|
||||
;
|
||||
|
||||
// var success = PInvoke.RegisterHotKey(_hwnd, _hotkeys.Count, modifiers, (uint)vk);
|
||||
// if (success)
|
||||
// {
|
||||
// _hotkeys.Add(new(globalHotkey, string.Empty));
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// foreach (var commandHotkey in settings.CommandHotkeys)
|
||||
// {
|
||||
// var key = commandHotkey.Hotkey;
|
||||
// if (key is not null)
|
||||
// {
|
||||
// if (settings.UseLowLevelGlobalHotkey)
|
||||
// {
|
||||
// _keyboardListener.SetHotkeyAction(key.Win, key.Ctrl, key.Shift, key.Alt, (byte)key.Code, commandHotkey.CommandId);
|
||||
// _hotkeys.Add(new(globalHotkey, string.Empty));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var vk = key.Code;
|
||||
// var modifiers =
|
||||
// (key.Alt ? HOT_KEY_MODIFIERS.MOD_ALT : 0) |
|
||||
// (key.Ctrl ? HOT_KEY_MODIFIERS.MOD_CONTROL : 0) |
|
||||
// (key.Shift ? HOT_KEY_MODIFIERS.MOD_SHIFT : 0) |
|
||||
// (key.Win ? HOT_KEY_MODIFIERS.MOD_WIN : 0)
|
||||
// ;
|
||||
// var success = PInvoke.RegisterHotKey(_hwnd, _hotkeys.Count, modifiers, (uint)vk);
|
||||
// if (success)
|
||||
// {
|
||||
// _hotkeys.Add(commandHotkey);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private void HandleSummon(string commandId)
|
||||
{
|
||||
if (_ignoreHotKeyWhenFullScreen)
|
||||
@@ -982,7 +913,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// _localKeyboardListener.Dispose();
|
||||
_keyboardService.Dispose();
|
||||
DisposeAcrylic();
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.CommandPalette.UI.Models\Microsoft.CommandPalette.UI.Models.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.CommandPalette.UI.Services\Microsoft.CommandPalette.UI.Services.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.CommandPalette.UI.ViewModels\Microsoft.CommandPalette.UI.ViewModels.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -2,24 +2,45 @@
|
||||
// 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.ComponentModel;
|
||||
using System.Text;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CommandPalette.UI.Models;
|
||||
using Microsoft.CommandPalette.UI.Models.Helpers;
|
||||
using CommunityToolkit.WinUI;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.UI.Models.Events;
|
||||
using Microsoft.CommandPalette.UI.Models.Messages;
|
||||
using Microsoft.CommandPalette.UI.Services;
|
||||
using Microsoft.CommandPalette.UI.ViewModels;
|
||||
using Microsoft.CommandPalette.ViewModels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using DispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue;
|
||||
|
||||
namespace Microsoft.CommandPalette.UI.Pages;
|
||||
|
||||
public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page
|
||||
public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
||||
IRecipient<NavigateBackMessage>,
|
||||
IRecipient<OpenSettingsMessage>,
|
||||
IRecipient<HotkeySummonMessage>,
|
||||
IRecipient<ShowDetailsMessage>,
|
||||
IRecipient<HideDetailsMessage>,
|
||||
IRecipient<ClearSearchMessage>,
|
||||
IRecipient<LaunchUriMessage>,
|
||||
IRecipient<SettingsWindowClosedMessage>,
|
||||
IRecipient<GoHomeMessage>,
|
||||
IRecipient<GoBackMessage>,
|
||||
IRecipient<ShowConfirmationMessage>,
|
||||
IRecipient<ShowToastMessage>,
|
||||
IRecipient<NavigateToPageMessage>,
|
||||
INotifyPropertyChanged,
|
||||
IDisposable
|
||||
{
|
||||
private readonly ShellViewModel viewModel;
|
||||
private readonly SettingsModel _settingsModel;
|
||||
private readonly SettingsService _settingsService;
|
||||
private readonly ILogger logger;
|
||||
private readonly DispatcherQueue _queue = DispatcherQueue.GetForCurrentThread();
|
||||
private readonly Microsoft.UI.Dispatching.DispatcherQueueTimer _debounceTimer = DispatcherQueue.GetForCurrentThread().CreateTimer();
|
||||
@@ -30,13 +51,31 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page
|
||||
|
||||
private readonly CompositeFormat _pageNavigatedAnnouncement;
|
||||
|
||||
public ShellPage(ShellViewModel viewModel, SettingsModel settingsModel, ILogger logger)
|
||||
public ShellPage(ShellViewModel viewModel, SettingsService settingsService, ILogger logger)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.viewModel = viewModel;
|
||||
_settingsModel = settingsModel;
|
||||
_settingsService = settingsService;
|
||||
this.logger = logger;
|
||||
|
||||
// how we are doing navigation around
|
||||
WeakReferenceMessenger.Default.Register<NavigateBackMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<OpenSettingsMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<HotkeySummonMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<SettingsWindowClosedMessage>(this);
|
||||
|
||||
WeakReferenceMessenger.Default.Register<ShowDetailsMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<HideDetailsMessage>(this);
|
||||
|
||||
WeakReferenceMessenger.Default.Register<ClearSearchMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<LaunchUriMessage>(this);
|
||||
|
||||
WeakReferenceMessenger.Default.Register<GoHomeMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<GoBackMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<ShowConfirmationMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<ShowToastMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigateToPageMessage>(this);
|
||||
|
||||
// AddHandler(PreviewKeyDownEvent, new KeyEventHandler(ShellPage_OnPreviewKeyDown), true);
|
||||
// AddHandler(KeyDownEvent, new KeyEventHandler(ShellPage_OnKeyDown), false);
|
||||
// AddHandler(PointerPressedEvent, new PointerEventHandler(ShellPage_OnPointerPressed), true);
|
||||
@@ -53,10 +92,218 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page
|
||||
{
|
||||
get
|
||||
{
|
||||
return _settingsModel.DisableAnimations ? _noAnimation : _slideRightTransition;
|
||||
return _settingsService.CurrentSettings.DisableAnimations ? _noAnimation : _slideRightTransition;
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(NavigateBackMessage message)
|
||||
{
|
||||
if (RootFrame.CanGoBack)
|
||||
{
|
||||
if (!message.FromBackspace ||
|
||||
_settingsService.CurrentSettings.BackspaceGoesBack)
|
||||
{
|
||||
GoBack();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!message.FromBackspace)
|
||||
{
|
||||
// If we can't go back then we must be at the top and thus escape again should quit.
|
||||
WeakReferenceMessenger.Default.Send<DismissMessage>();
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new DismissedOnEscEvent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(NavigateToPageMessage message)
|
||||
{
|
||||
// TODO GH #526 This needs more better locking too
|
||||
_ = _queue.TryEnqueue(() =>
|
||||
{
|
||||
// Also hide our details pane about here, if we had one
|
||||
// HideDetails();
|
||||
|
||||
// Navigate to the appropriate host page for that VM
|
||||
// RootFrame.Navigate(
|
||||
// message.Page switch
|
||||
// {
|
||||
// ListViewModel => typeof(ListPage),
|
||||
// ContentPageViewModel => typeof(ContentPage),
|
||||
// _ => throw new NotSupportedException(),
|
||||
// },
|
||||
// new AsyncNavigationRequest(message.Page, message.CancellationToken),
|
||||
// message.WithAnimation ? DefaultPageAnimation : _noAnimation);
|
||||
// PowerToysTelemetry.Log.WriteEvent(new OpenPageEvent(RootFrame.BackStackDepth, message.Page.Id));
|
||||
// if (!viewModel.IsNested)
|
||||
// {
|
||||
// // todo BODGY
|
||||
// RootFrame.BackStack.Clear();
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
public void Receive(ShowConfirmationMessage message)
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await HandleConfirmArgsOnUiThread(message.Args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Receive(ShowToastMessage message)
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
// _toast.ShowToast(message.Message);
|
||||
});
|
||||
}
|
||||
|
||||
// This gets called from the UI thread
|
||||
private async Task HandleConfirmArgsOnUiThread(IConfirmationArgs? args)
|
||||
{
|
||||
if (args is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ConfirmResultViewModel vm = new(args, new(ViewModel.CurrentPage));
|
||||
var initializeDialogTask = Task.Run(() => { InitializeConfirmationDialog(vm); });
|
||||
await initializeDialogTask;
|
||||
|
||||
var resourceLoader = Microsoft.CmdPal.UI.Helpers.ResourceLoaderInstance.ResourceLoader;
|
||||
var confirmText = resourceLoader.GetString("ConfirmationDialog_ConfirmButtonText");
|
||||
var cancelText = resourceLoader.GetString("ConfirmationDialog_CancelButtonText");
|
||||
|
||||
var name = string.IsNullOrEmpty(vm.PrimaryCommand.Name) ? confirmText : vm.PrimaryCommand.Name;
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
Title = vm.Title,
|
||||
Content = vm.Description,
|
||||
PrimaryButtonText = name,
|
||||
CloseButtonText = cancelText,
|
||||
XamlRoot = this.XamlRoot,
|
||||
};
|
||||
|
||||
if (vm.IsPrimaryCommandCritical)
|
||||
{
|
||||
dialog.DefaultButton = ContentDialogButton.Close;
|
||||
|
||||
// TODO: Maybe we need to style the primary button to be red?
|
||||
// dialog.PrimaryButtonStyle = new Style(typeof(Button))
|
||||
// {
|
||||
// Setters =
|
||||
// {
|
||||
// new Setter(Button.ForegroundProperty, new SolidColorBrush(Colors.Red)),
|
||||
// new Setter(Button.BackgroundProperty, new SolidColorBrush(Colors.Red)),
|
||||
// },
|
||||
// };
|
||||
}
|
||||
|
||||
var result = await dialog.ShowAsync();
|
||||
if (result == ContentDialogResult.Primary)
|
||||
{
|
||||
var performMessage = new PerformCommandMessage(vm);
|
||||
WeakReferenceMessenger.Default.Send(performMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cancel
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(OpenSettingsMessage message)
|
||||
{
|
||||
_ = DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
OpenSettings();
|
||||
});
|
||||
}
|
||||
|
||||
public void OpenSettings()
|
||||
{
|
||||
if (_settingsWindow is null)
|
||||
{
|
||||
_settingsWindow = new SettingsWindow();
|
||||
}
|
||||
|
||||
_settingsWindow.Activate();
|
||||
_settingsWindow.BringToFront();
|
||||
}
|
||||
|
||||
public void Receive(ShowDetailsMessage message)
|
||||
{
|
||||
if (ViewModel is not null &&
|
||||
ViewModel.CurrentPage is not null)
|
||||
{
|
||||
if (ViewModel.CurrentPage.PageContext.TryGetTarget(out var pageContext))
|
||||
{
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
// TERRIBLE HACK TODO GH #245
|
||||
// There's weird wacky bugs with debounce currently.
|
||||
if (!ViewModel.IsDetailsVisible)
|
||||
{
|
||||
ViewModel.Details = message.Details;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasHeroImage)));
|
||||
ViewModel.IsDetailsVisible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// GH #322:
|
||||
// For inexplicable reasons, if you try to change the details too fast,
|
||||
// we'll explode. This seemingly only happens if you change the details
|
||||
// while we're also scrolling a new list view item into view.
|
||||
_debounceTimer.Debounce(
|
||||
() =>
|
||||
{
|
||||
ViewModel.Details = message.Details;
|
||||
|
||||
// Trigger a re-evaluation of whether we have a hero image based on
|
||||
// the current theme
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasHeroImage)));
|
||||
},
|
||||
interval: TimeSpan.FromMilliseconds(50),
|
||||
immediate: ViewModel.IsDetailsVisible == false);
|
||||
ViewModel.IsDetailsVisible = true;
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
pageContext.Scheduler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(HideDetailsMessage message) => HideDetails();
|
||||
|
||||
public void Receive(LaunchUriMessage message) => _ = global::Windows.System.Launcher.LaunchUriAsync(message.Uri);
|
||||
|
||||
private void HideDetails()
|
||||
{
|
||||
ViewModel.Details = null;
|
||||
ViewModel.IsDetailsVisible = false;
|
||||
}
|
||||
|
||||
public void Receive(ClearSearchMessage message) => SearchBox.ClearSearch();
|
||||
|
||||
public void Receive(HotkeySummonMessage message)
|
||||
{
|
||||
_ = DispatcherQueue.TryEnqueue(() => SummonOnUiThread(message));
|
||||
}
|
||||
|
||||
public void Receive(SettingsWindowClosedMessage message) => _settingsWindow = null;
|
||||
|
||||
|
||||
private void SummonOnUiThread(HotkeySummonMessage message)
|
||||
{
|
||||
var commandId = message.CommandId;
|
||||
@@ -69,11 +316,11 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page
|
||||
// Depending on the settings, either
|
||||
// * Go home, or
|
||||
// * Select the search text (if we should remain open on this page)
|
||||
if (_settingsModel.AutoGoHomeInterval == TimeSpan.Zero)
|
||||
if (_settingsService.CurrentSettings.AutoGoHomeInterval == TimeSpan.Zero)
|
||||
{
|
||||
// GoHome(false);
|
||||
GoHome(false);
|
||||
}
|
||||
else if (_settingsModel.HighlightSearchOnActivate)
|
||||
else if (_settingsService.CurrentSettings.HighlightSearchOnActivate)
|
||||
{
|
||||
// SearchBox.SelectSearch();
|
||||
}
|
||||
|
||||
@@ -7,17 +7,11 @@ using System.Globalization;
|
||||
using System.Text;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.WinUI;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Core.ViewModels;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.Events;
|
||||
using Microsoft.CmdPal.UI.Helpers;
|
||||
using Microsoft.CmdPal.UI.Messages;
|
||||
using Microsoft.CmdPal.UI.Settings;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Input;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
Reference in New Issue
Block a user