Add taskbar indicators

This commit is contained in:
Aaron Junker
2025-06-13 23:37:54 +02:00
parent 0b823ea8bd
commit 7596e965ef
17 changed files with 797 additions and 173 deletions

View File

@@ -718,6 +718,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.FuzzingTest", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShortcutGuide.IndexYmlGenerator", "src\modules\ShortcutGuideV2\ShortcutGuide.IndexYmlGenerator\ShortcutGuide.IndexYmlGenerator\ShortcutGuide.IndexYmlGenerator.csproj", "{D640B00C-9149-4C4F-8B7D-E2B8B2590A0B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuide.CPPProject", "src\modules\ShortcutGuideV2\ShortcutGuide.CPPProject\ShortcutGuide.CPPProject.vcxproj", "{C992FD2C-83B8-4941-9FC1-09730068D8EC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -2632,6 +2634,14 @@ Global
{D640B00C-9149-4C4F-8B7D-E2B8B2590A0B}.Release|ARM64.Build.0 = Release|ARM64
{D640B00C-9149-4C4F-8B7D-E2B8B2590A0B}.Release|x64.ActiveCfg = Release|x64
{D640B00C-9149-4C4F-8B7D-E2B8B2590A0B}.Release|x64.Build.0 = Release|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Debug|ARM64.ActiveCfg = Debug|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Debug|ARM64.Build.0 = Debug|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Debug|x64.ActiveCfg = Debug|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Debug|x64.Build.0 = Debug|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Release|ARM64.ActiveCfg = Release|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Release|ARM64.Build.0 = Release|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Release|x64.ActiveCfg = Release|x64
{C992FD2C-83B8-4941-9FC1-09730068D8EC}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2908,6 +2918,7 @@ Global
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{D640B00C-9149-4C4F-8B7D-E2B8B2590A0B} = {21275C57-1C20-4F07-8A56-21BFA8363BDB}
{C992FD2C-83B8-4941-9FC1-09730068D8EC} = {21275C57-1C20-4F07-8A56-21BFA8363BDB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@@ -65,14 +65,12 @@
<ClInclude Include="Generated Files\resource.h" />
<ClInclude Include="native_event_waiter.h" />
<ClInclude Include="overlay_window.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.base.h" />
<ClInclude Include="ShortcutGuideSettings.h" />
<ClInclude Include="ShortcutGuideConstants.h" />
<ClInclude Include="shortcut_guide.h" />
<ClInclude Include="start_visible.h" />
<ClInclude Include="target_state.h" />
<ClInclude Include="tasklist_positions.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
<ItemGroup>
@@ -83,13 +81,9 @@
<ClCompile Include="main.cpp" />
<ClCompile Include="native_event_waiter.cpp" />
<ClCompile Include="overlay_window.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="shortcut_guide.cpp" />
<ClCompile Include="start_visible.cpp" />
<ClCompile Include="target_state.cpp" />
<ClCompile Include="tasklist_positions.cpp" />
<ClCompile Include="trace.cpp" />
</ItemGroup>
<ItemGroup>

View File

@@ -18,9 +18,6 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="animation.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -51,9 +48,6 @@
<ClInclude Include="target_state.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="tasklist_positions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -68,9 +62,6 @@
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -101,9 +92,6 @@
<ClCompile Include="target_state.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tasklist_positions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="trace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -116,7 +104,79 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="Assets\ShortcutGuide\**">
<CopyFileToFolders Include="Assets\ShortcutGuide\1.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\2.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\3.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\4.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\5.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\6.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\7.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\8.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\9.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\no_active_window.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\overlay.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\overlay_portrait.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\0.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\1.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\2.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\3.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\4.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\5.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\6.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\7.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\8.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\9.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\no_active_window.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\overlay.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
<CopyFileToFolders Include="Assets\ShortcutGuide\overlay_portrait.svg">
<Filter>Resource Files</Filter>
</CopyFileToFolders>
</ItemGroup>

View File

@@ -25,5 +25,4 @@
#include <tuple>
#include <unordered_set>
#include <string>
#include <filesystem>
#include <common/logger/logger.h>
#include <filesystem>

View File

@@ -1,116 +1,193 @@
#include "pch.h"
#include "tasklist_positions.h"
#include <windows.h>
#include <vector>
#include <winrt/base.h>
#include <UIAutomation.h>
void Tasklist::update()
extern "C"
{
// Get HWND of the tasklist
auto tasklist_hwnd = FindWindowA("Shell_TrayWnd", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "ReBarWindow32", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskSwWClass", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExA(tasklist_hwnd, 0, "MSTaskListWClass", nullptr);
if (!tasklist_hwnd)
return;
if (!automation)
{
winrt::check_hresult(CoCreateInstance(CLSID_CUIAutomation,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IUIAutomation,
automation.put_void()));
winrt::check_hresult(automation->CreateTrueCondition(true_condition.put()));
}
element = nullptr;
winrt::check_hresult(automation->ElementFromHandle(tasklist_hwnd, element.put()));
}
winrt::com_ptr<IUIAutomation> automation;
winrt::com_ptr<IUIAutomationElement> element;
winrt::com_ptr<IUIAutomationCondition> true_condition;
bool Tasklist::update_buttons(std::vector<TasklistButton>& buttons)
{
if (!automation || !element)
// Helper to get the taskbar HWND for the monitor under the cursor
HWND GetTaskbarHwndForCursorMonitor(HMONITOR monitor)
{
return false;
}
winrt::com_ptr<IUIAutomationElementArray> elements;
if (element->FindAll(TreeScope_Children, true_condition.get(), elements.put()) < 0)
return false;
if (!elements)
return false;
int count;
if (elements->get_Length(&count) < 0)
return false;
winrt::com_ptr<IUIAutomationElement> child;
std::vector<TasklistButton> found_buttons;
found_buttons.reserve(count);
for (int i = 0; i < count; ++i)
{
child = nullptr;
if (elements->GetElement(i, child.put()) < 0)
return false;
TasklistButton button;
if (VARIANT var_rect; child->GetCurrentPropertyValue(UIA_BoundingRectanglePropertyId, &var_rect) >= 0)
POINT pt;
if (!GetCursorPos(&pt))
return nullptr;
// Find the primary taskbar
HWND primaryTaskbar = FindWindowW(L"Shell_TrayWnd", nullptr);
if (primaryTaskbar)
{
if (var_rect.vt == (VT_R8 | VT_ARRAY))
MONITORINFO mi = { sizeof(mi) };
if (GetWindowRect(primaryTaskbar, &mi.rcMonitor))
{
LONG pos;
double value;
pos = 0;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.x = static_cast<long>(value);
pos = 1;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.y = static_cast<long>(value);
pos = 2;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.width = static_cast<long>(value);
pos = 3;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.height = static_cast<long>(value);
HMONITOR primaryMonitor = MonitorFromRect(&mi.rcMonitor, MONITOR_DEFAULTTONEAREST);
if (primaryMonitor == monitor)
return primaryTaskbar;
}
VariantClear(&var_rect);
}
// Find the secondary taskbar(s)
HWND secondaryTaskbar = nullptr;
while ((secondaryTaskbar = FindWindowExW(nullptr, secondaryTaskbar, L"Shell_SecondaryTrayWnd", nullptr)) != nullptr)
{
MONITORINFO mi = { sizeof(mi) };
RECT rc;
if (GetWindowRect(secondaryTaskbar, &rc))
{
HMONITOR monitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST);
if (monitor == monitor)
return secondaryTaskbar;
}
}
return nullptr;
}
__declspec(dllexport) void update(HMONITOR monitor)
{
// Get HWND of the tasklist for the monitor under the cursor
auto taskbar_hwnd = GetTaskbarHwndForCursorMonitor(monitor);
if (!taskbar_hwnd)
return;
wchar_t class_name[64] = {};
GetClassNameW(taskbar_hwnd, class_name, 64);
HWND tasklist_hwnd = nullptr;
if (wcscmp(class_name, L"Shell_TrayWnd") == 0)
{
// Primary taskbar structure
tasklist_hwnd = FindWindowExW(taskbar_hwnd, 0, L"ReBarWindow32", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExW(tasklist_hwnd, 0, L"MSTaskSwWClass", nullptr);
if (!tasklist_hwnd)
return;
tasklist_hwnd = FindWindowExW(tasklist_hwnd, 0, L"MSTaskListWClass", nullptr);
if (!tasklist_hwnd)
return;
}
else if (wcscmp(class_name, L"Shell_SecondaryTrayWnd") == 0)
{
// Secondary taskbar structure
HWND workerw = FindWindowExW(taskbar_hwnd, 0, L"WorkerW", nullptr);
if (!workerw)
return;
tasklist_hwnd = FindWindowExW(workerw, 0, L"MSTaskListWClass", nullptr);
if (!tasklist_hwnd)
return;
}
else
{
// Unknown taskbar type
return;
}
if (!automation)
{
winrt::check_hresult(CoCreateInstance(CLSID_CUIAutomation,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IUIAutomation,
automation.put_void()));
winrt::check_hresult(automation->CreateTrueCondition(true_condition.put()));
}
element = nullptr;
winrt::check_hresult(automation->ElementFromHandle(tasklist_hwnd, element.put()));
}
__declspec(dllexport) bool update_buttons(std::vector<TasklistButton>& buttons)
{
if (!automation || !element)
{
return false;
}
if (BSTR automation_id; child->get_CurrentAutomationId(&automation_id) >= 0)
winrt::com_ptr<IUIAutomationElementArray> elements;
if (element->FindAll(TreeScope_Children, true_condition.get(), elements.put()) < 0)
return false;
if (!elements)
return false;
int count;
if (elements->get_Length(&count) < 0)
return false;
winrt::com_ptr<IUIAutomationElement> child;
std::vector<TasklistButton> found_buttons;
found_buttons.reserve(count);
for (int i = 0; i < count; ++i)
{
button.name = automation_id;
SysFreeString(automation_id);
child = nullptr;
if (elements->GetElement(i, child.put()) < 0)
return false;
TasklistButton button;
if (VARIANT var_rect; child->GetCurrentPropertyValue(UIA_BoundingRectanglePropertyId, &var_rect) >= 0)
{
if (var_rect.vt == (VT_R8 | VT_ARRAY))
{
LONG pos;
double value;
pos = 0;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.x = static_cast<long>(value);
pos = 1;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.y = static_cast<long>(value);
pos = 2;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.width = static_cast<long>(value);
pos = 3;
SafeArrayGetElement(var_rect.parray, &pos, &value);
button.height = static_cast<long>(value);
}
VariantClear(&var_rect);
}
else
{
return false;
}
if (BSTR automation_id; child->get_CurrentAutomationId(&automation_id) >= 0)
{
wcsncpy_s(button.name, automation_id, _countof(button.name));
SysFreeString(automation_id);
}
found_buttons.push_back(button);
}
found_buttons.push_back(button);
// assign keynums
buttons.clear();
for (auto& button : found_buttons)
{
if (buttons.empty())
{
button.keynum = 1;
buttons.push_back(std::move(button));
}
else
{
if (button.x < buttons.back().x || button.y < buttons.back().y) // skip 2nd row
break;
if (wcsncmp(button.name, buttons.back().name, _countof(button.name)) == 0)
continue; // skip buttons from the same app
button.keynum = buttons.back().keynum + 1;
buttons.push_back(std::move(button));
if (buttons.back().keynum == 10)
break; // no more than 10 buttons
}
}
return true;
}
// assign keynums
buttons.clear();
for (auto& button : found_buttons)
__declspec(dllexport) TasklistButton* get_buttons(HMONITOR monitor, int* size)
{
if (buttons.empty())
{
button.keynum = 1;
buttons.push_back(std::move(button));
}
else
{
if (button.x < buttons.back().x || button.y < buttons.back().y) // skip 2nd row
break;
if (button.name == buttons.back().name)
continue; // skip buttons from the same app
button.keynum = buttons.back().keynum + 1;
buttons.push_back(std::move(button));
if (buttons.back().keynum == 10)
break; // no more than 10 buttons
}
update(monitor);
static std::vector<TasklistButton> buttons;
update_buttons(buttons);
*size = static_cast<int>(buttons.size());
return buttons.data();
}
return true;
}
std::vector<TasklistButton> Tasklist::get_buttons()
{
std::vector<TasklistButton> buttons;
update_buttons(buttons);
return buttons;
}

View File

@@ -7,23 +7,10 @@
struct TasklistButton
{
std::wstring name;
long x{};
long y{};
long width{};
long height{};
long keynum{};
};
class Tasklist
{
public:
void update();
std::vector<TasklistButton> get_buttons();
bool update_buttons(std::vector<TasklistButton>& buttons);
private:
winrt::com_ptr<IUIAutomation> automation;
winrt::com_ptr<IUIAutomationElement> element;
winrt::com_ptr<IUIAutomationCondition> true_condition;
wchar_t name[256];
int x;
int y;
int width;
int height;
int keynum;
};

View File

@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<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>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{c992fd2c-83b8-4941-9fc1-09730068d8ec}</ProjectGuid>
<RootNamespace>ShortcutGuideCPPProject</RootNamespace>
<WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</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|Win32'">
<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|Win32'">
<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)'=='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'">
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\ShortcutGuide\ShortcutGuide\pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\..\ShortcutGuide\ShortcutGuide\tasklist_positions.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\ShortcutGuide\ShortcutGuide\pch.h" />
<ClInclude Include="..\..\ShortcutGuide\ShortcutGuide\tasklist_positions.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\ShortcutGuide\ShortcutGuide\tasklist_positions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\ShortcutGuide\ShortcutGuide\pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\ShortcutGuide\ShortcutGuide\tasklist_positions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\ShortcutGuide\ShortcutGuide\pch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -12,6 +12,21 @@ Shortcuts:
Alt: true
Keys:
- F4
- Name: Test shortcut
Shortcut:
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- K
- Win: false
Ctrl: true
Shift: false
Alt: false
Keys:
- C
- Name: Open shutdown box
Description: When no windows are open
Shortcut:
@@ -29,12 +44,6 @@ Shortcuts:
Alt: true
Keys:
- Esc
- Win: false
Ctrl: false
Shift: false
Alt: true
Keys:
- Esc
- Name: Reveal typed password
Description: On sign-in screen
Shortcut:

View File

@@ -19,6 +19,7 @@ namespace ShortcutGuide
public static Rect GetWorkAreaForDisplayWithWindow(IntPtr hwnd)
{
foundMonitorIndex = -1;
monitorIndex = 0;
var monitor = MonitorFromWindow(hwnd, (int)MonitorFromWindowDwFlags.MONITOR_DEFAULTTONEAREST);
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnumProc, new LPARAM(monitor));
return MonitorInfo.GetDisplayMonitors()[foundMonitorIndex].RectWork;

View File

@@ -1,27 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace ShortcutGuide.Helpers
{
internal sealed class TaskListPositions
{
public static List<RECT> GetTaskbarIconPositions()
{
throw new NotImplementedException();
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
}
}

View File

@@ -26,10 +26,10 @@ internal static partial class NativeMethods
internal static partial int SetWindowLongW(IntPtr hWnd, int nIndex, int dwNewLong);
[LibraryImport("user32.dll", StringMarshalling = StringMarshalling.Utf16)]
internal static partial int FindWindowA(in string lpClassName, in string? lpWindowName);
internal static partial IntPtr FindWindowA(in string lpClassName, in string? lpWindowName);
[LibraryImport("user32.dll", StringMarshalling = StringMarshalling.Utf16)]
internal static partial int FindWindowExA(int hwndParent, int hwndChildAfter, in string lpClassName, in string? lpWindowName);
public static partial IntPtr FindWindowExA(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[LibraryImport("User32.dll")]
internal static partial IntPtr MonitorFromWindow(int hwnd, int dwFlags);
@@ -47,6 +47,14 @@ internal static partial class NativeMethods
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[DllImport("ole32.dll", SetLastError = true)]
public static extern uint CoCreateInstance(
in Guid rclsid,
IntPtr pUnkOuter,
uint dwClsContext,
in Guid riid,
out IntPtr ppv);
public struct POINT
{
public int X;

View File

@@ -60,6 +60,17 @@
<ItemGroup>
<ApplicationDefinition Include="ShortcutGuideXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<COMReference Include="UIAutomationClient">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>944de083-8fb8-45cf-bcb7-c477acb2f897</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<Content Include="Assets\Hosts\Hosts.ico" />
@@ -95,6 +106,7 @@
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\ShortcutGuide.CPPProject\ShortcutGuide.CPPProject.vcxproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resource.Designer.cs">

View File

@@ -28,6 +28,8 @@ namespace ShortcutGuide
/// </summary>
public sealed partial class MainWindow : WindowEx
{
public static nint WindowHwnd { get; set; }
private AppWindow _appWindow;
private string[] _currentApplicationIds;
@@ -41,6 +43,7 @@ namespace ShortcutGuide
Title = Resource.ResourceManager.GetString("Title", CultureInfo.InvariantCulture)!;
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WindowHwnd = hwnd;
WindowId windowId = Win32Interop.GetWindowIdFromWindow(hwnd);
_appWindow = AppWindow.GetFromWindowId(windowId);
#if !DEBUG
@@ -75,7 +78,9 @@ namespace ShortcutGuide
{
if (e.WindowActivationState == WindowActivationState.Deactivated)
{
#if !DEBUG
Environment.Exit(0);
#endif
}
if (!_setPosition)
@@ -96,6 +101,16 @@ namespace ShortcutGuide
// Move top of the window to the center of the monitor
_appWindow.Move(new PointInt32((int)monitorRect.X, (int)(monitorRect.Y + (int)(monitorRect.Height / 2))));
_setPosition = true;
AppWindow.Changed += (_, a) =>
{
if (a.DidPresenterChange)
{
Rect monitorRect = DisplayHelper.GetWorkAreaForDisplayWithWindow(hwnd);
float dpiScale = DpiHelper.GetDPIScaleForWindow((int)hwnd);
this.SetWindowSize(monitorRect.Width / dpiScale, monitorRect.Height / dpiScale / 2);
_appWindow.Move(new PointInt32((int)monitorRect.X, (int)(monitorRect.Y + (int)(monitorRect.Height / 2))));
}
};
}
if (WindowSelector.Items.Count == 0)

View File

@@ -38,6 +38,7 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<SelectorBar Grid.Row="0" x:Name="CategorySelector" />
<TextBlock x:Name="ErrorMessage" Style="{StaticResource SubheaderTextBlockStyle}" Grid.Row="1" Margin="6,0,6,0"></TextBlock>
@@ -78,5 +79,47 @@
</GridView>
</Grid>
</ScrollViewer>
<Canvas Grid.Row="2" x:Name="TaskbarIndicators" Visibility="Collapsed" Height="20">
<Canvas x:Name="TaskbarIndicator1" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="1" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
<Canvas x:Name="TaskbarIndicator2" Canvas.Left="20" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="2" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
<Canvas x:Name="TaskbarIndicator3" Canvas.Left="40" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="3" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
<Canvas x:Name="TaskbarIndicator4" Canvas.Left="60" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="4" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
<Canvas x:Name="TaskbarIndicator5" Canvas.Left="80" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="5" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
<Canvas x:Name="TaskbarIndicator6" Canvas.Left="100" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="6" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
<Canvas x:Name="TaskbarIndicator7" Canvas.Left="120" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="7" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
<Canvas x:Name="TaskbarIndicator8" Canvas.Left="140" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="8" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
<Canvas x:Name="TaskbarIndicator9" Canvas.Left="160" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="9" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
<Canvas x:Name="TaskbarIndicator10" Canvas.Left="180" Height="10" Width="10">
<Rectangle Fill="Blue" Height="10" Width="10" />
<TextBlock Text="0" Foreground="White" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold"/>
</Canvas>
</Canvas>
</Grid>
</Page>

View File

@@ -7,13 +7,16 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using ShortcutGuide;
using Microsoft.UI.Xaml.Media.Animation;
using Microsoft.UI.Xaml.Shapes;
using ShortcutGuide.Models;
using Windows.Foundation;
@@ -21,6 +24,8 @@ namespace ShortcutGuide
{
public sealed partial class ShortcutView : Page, INotifyPropertyChanged
{
private readonly DispatcherTimer _taskbarUpdateTimer = new() { Interval = TimeSpan.FromMilliseconds(500) };
private bool _showTaskbarShortcuts = true;
private ShortcutFile shortcutList = ManifestInterpreter.GetShortcutsOfApplication(ShortcutPageParameters.CurrentPageName);
public ShortcutView()
@@ -41,7 +46,7 @@ namespace ShortcutGuide
switch (category.SectionName)
{
case string name when name.StartsWith("<TASKBAR1-9>", StringComparison.Ordinal):
// Todo: Implement GetTaskbarIconPositions
_showTaskbarShortcuts = true;
break;
case string name when name.StartsWith('<') && name.EndsWith('>'):
break;
@@ -69,6 +74,13 @@ namespace ShortcutGuide
ShortcutPageParameters.PinnedShortcuts.Add(ShortcutPageParameters.CurrentPageName, []);
}
if (_showTaskbarShortcuts)
{
TaskbarIndicators.Visibility = Visibility.Visible;
_taskbarUpdateTimer.Tick += UpdateTaskbarIndicators;
_taskbarUpdateTimer.Start();
}
OpenOverview();
}
catch (Exception)
@@ -79,6 +91,59 @@ namespace ShortcutGuide
}
}
private void UpdateTaskbarIndicators(object? sender, object? e)
{
var buttons = TasklistPositions.GetButtons();
Canvas[] canvases = [
TaskbarIndicator1,
TaskbarIndicator2,
TaskbarIndicator3,
TaskbarIndicator4,
TaskbarIndicator5,
TaskbarIndicator6,
TaskbarIndicator7,
TaskbarIndicator8,
TaskbarIndicator9,
TaskbarIndicator10,
];
for (int i = 0; i < canvases.Length; i++)
{
if (i < buttons.Length)
{
canvases[i].Visibility = Visibility.Visible;
Rect workArea = DisplayHelper.GetWorkAreaForDisplayWithWindow(MainWindow.WindowHwnd);
DoubleAnimation animation = new DoubleAnimation
{
To = (buttons[i].X - workArea.Left) / DpiHelper.GetDPIScaleForWindow(MainWindow.WindowHwnd.ToInt32()),
Duration = TimeSpan.FromMilliseconds(500),
};
// Create the storyboard
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
// Set the target and property
Storyboard.SetTarget(animation, canvases[i]);
Storyboard.SetTargetProperty(animation, "(Canvas.Left)");
// Start the animation
storyboard.Begin();
canvases[i].Width = buttons[i].Width / DpiHelper.GetDPIScaleForWindow(MainWindow.WindowHwnd.ToInt32());
canvases[i].Height = buttons[i].Height / DpiHelper.GetDPIScaleForWindow(MainWindow.WindowHwnd.ToInt32());
((Rectangle)canvases[i].Children[0]).Width = buttons[i].Width / DpiHelper.GetDPIScaleForWindow(MainWindow.WindowHwnd.ToInt32());
((Rectangle)canvases[i].Children[0]).Height = buttons[i].Height / DpiHelper.GetDPIScaleForWindow(MainWindow.WindowHwnd.ToInt32());
((TextBlock)canvases[i].Children[1]).Width = buttons[i].Width / DpiHelper.GetDPIScaleForWindow(MainWindow.WindowHwnd.ToInt32());
((TextBlock)canvases[i].Children[1]).Height = buttons[i].Height / DpiHelper.GetDPIScaleForWindow(MainWindow.WindowHwnd.ToInt32());
}
else
{
canvases[i].Visibility = Visibility.Collapsed;
}
}
}
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

View File

@@ -0,0 +1,188 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UIAutomationClient;
namespace ShortcutGuide
{
internal sealed partial class TasklistPositions
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TasklistButton
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Name;
public int X;
public int Y;
public int Width;
public int Height;
public int Keynum;
}
/*
private IUIAutomation? _automation;
private IUIAutomationElement? _element;
private IUIAutomationCondition? _trueCondition;
public void Update()
{
// Get HWND of the tasklist
var tasklistHwnd = NativeMethods.FindWindowA("Shell_TrayWnd", null);
if (tasklistHwnd == IntPtr.Zero)
{
return;
}
tasklistHwnd = NativeMethods.FindWindowExA(tasklistHwnd, IntPtr.Zero, "ReBarWindow32", string.Empty);
if (tasklistHwnd == IntPtr.Zero)
{
return;
}
tasklistHwnd = NativeMethods.FindWindowExA(tasklistHwnd, IntPtr.Zero, "MSTaskSwWClass", string.Empty);
if (tasklistHwnd == IntPtr.Zero)
{
return;
}
tasklistHwnd = NativeMethods.FindWindowExA(tasklistHwnd, IntPtr.Zero, "MSTaskListWClass", string.Empty);
if (tasklistHwnd == IntPtr.Zero)
{
return;
}
if (_automation == null)
{
_automation = new CUIAutomation();
_trueCondition = _automation.CreateTrueCondition();
}
_element = null;
_element = _automation.ElementFromHandle(tasklistHwnd);
}
public bool UpdateButtons(List<TasklistButton> buttons)
{
if (_automation == null || _element == null)
{
return false;
}
IUIAutomationElementArray elements = _element.FindAll(TreeScope.TreeScope_Children, _trueCondition);
if (elements == null)
{
return false;
}
int count = elements.Length;
var foundButtons = new List<TasklistButton>(count);
for (int i = 0; i < count; ++i)
{
var child = elements.GetElement(i);
var button = default(TasklistButton);
object rectObj = child.GetCurrentPropertyValue(30001);
if (rectObj is double[] arr && arr.Length == 4)
{
button.X = (long)arr[0];
button.Y = (long)arr[1];
button.Width = (long)arr[2];
button.Height = (long)arr[3];
}
else if (rectObj is Windows.Foundation.Rect wrect)
{
button.X = (long)wrect.X;
button.Y = (long)wrect.Y;
button.Width = (long)wrect.Width;
button.Height = (long)wrect.Height;
}
else
{
System.Diagnostics.Debug.WriteLine($"rectObj type: {rectObj?.GetType()} value: {rectObj}");
continue; // Don't return false, just skip
}
object nameObj = child.GetCurrentPropertyValue(30011);
button.Name = nameObj as string ?? string.Empty;
foundButtons.Add(button);
}
// assign keynums
buttons.Clear();
foreach (var button in foundButtons)
{
if (buttons.Count == 0)
{
var b = button;
b.KeyNumber = 1;
buttons.Add(b);
}
else
{
var last = buttons[^1];
if (button.X < last.X || button.Y < last.Y)
{
break;
}
if (button.Name == last.Name)
{
continue;
}
var b = button;
b.KeyNumber = last.KeyNumber + 1;
buttons.Add(b);
if (b.KeyNumber == 10)
{
break;
}
}
}
return true;
}*/
[DllImport("ShortcutGuide.CPPProject.dll", EntryPoint = "get_buttons")]
public static extern IntPtr GetTasklistButtons(nint monitor, out int size);
[LibraryImport("User32.dll")]
private static partial IntPtr MonitorFromWindow(nint hwnd, int dwFlags);
public static TasklistButton[] GetButtons()
{
var monitor = MonitorFromWindow(MainWindow.WindowHwnd, 0);
IntPtr ptr = GetTasklistButtons(monitor, out int size);
if (ptr == IntPtr.Zero)
{
return [];
}
if (size <= 0)
{
return [];
}
TasklistButton[] buttons = new TasklistButton[size];
IntPtr currentPtr = ptr;
for (int i = 0; i < size; i++)
{
buttons[i] = Marshal.PtrToStructure<TasklistButton>(currentPtr);
currentPtr += Marshal.SizeOf<TasklistButton>();
}
return buttons;
}
}
}