Moved TaskbarButtonMonitor

This commit is contained in:
Dan Clark
2024-11-02 21:06:58 +00:00
parent 81e39f9895
commit 7a4a299262
12 changed files with 224 additions and 31 deletions
+7
View File
@@ -0,0 +1,7 @@
using Toolkit.Foundation;
namespace Toolkit.Windows;
public interface ITaskbarButtonMonitor :
IInitialization,
IDisposable;
+1 -2
View File
@@ -50,8 +50,7 @@ public class PointerMonitor(IPublisher publisher) :
{
if (nCode >= 0)
{
if (TryGetPointerLocation(out var location))
if (TryGetPointerLocation(out PointerLocation? location))
{
switch ((uint)wParam.Value)
{
+2 -2
View File
@@ -29,7 +29,7 @@ public class Screen
}
else
{
var monitorData = GetMonitorData(monitorHandle);
MonitorData monitorData = GetMonitorData(monitorHandle);
Bounds = new Rect(monitorData.MonitorRect.left, monitorData.MonitorRect.top,
monitorData.MonitorRect.right - monitorData.MonitorRect.left,
@@ -95,7 +95,7 @@ public class Screen
return SystemInformationHelper.WorkingArea;
}
var monitorData = GetMonitorData(_monitorHandle);
MonitorData monitorData = GetMonitorData(_monitorHandle);
return new Rect(monitorData.WorkAreaRect.left, monitorData.WorkAreaRect.top, monitorData.WorkAreaRect.right - monitorData.WorkAreaRect.left, monitorData.WorkAreaRect.bottom - monitorData.WorkAreaRect.top);
}
+1 -1
View File
@@ -22,7 +22,7 @@ internal static class SystemInformationHelper
private static Rect GetWorkingArea()
{
var rect = new RECT();
RECT rect = new RECT();
SystemParametersInfo(SPI_GETWORKAREA, 0, ref rect, 0);
return new Rect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+4 -4
View File
@@ -23,13 +23,13 @@ public class Taskbar(ISubscriber subscriber,
public TaskbarState GetCurrentState()
{
var handle = GetHandle();
var state = new TaskbarState
nint handle = GetHandle();
TaskbarState state = new TaskbarState
{
Screen = Screen.FromHandle(handle)
};
var appBarData = PInvoke.GetAppBarData(handle);
PInvoke.AppBarData appBarData = PInvoke.GetAppBarData(handle);
PInvoke.GetAppBarPosition(ref appBarData);
state.Rect = appBarData.rect.ToRect();
@@ -65,7 +65,7 @@ public class Taskbar(ISubscriber subscriber,
public Task Handle(PointerMovedEventArgs args)
{
nint taskbarHandle = GetHandle();
if (WindowHelper.TryGetBounds(taskbarHandle, out var rect))
if (WindowHelper.TryGetBounds(taskbarHandle, out Rect? rect))
{
if (args.Location.IsWithinBounds(rect))
{
@@ -0,0 +1,3 @@
namespace Toolkit.Windows;
public record TaskbarButtonCreatedEventArgs(TaskbarButton Button);
+158
View File
@@ -0,0 +1,158 @@
using System.Diagnostics;
using Toolkit.Foundation;
using UIAutomationClient;
namespace Toolkit.Windows;
public class TaskbarButtonMonitor :
ITaskbarButtonMonitor
{
private readonly IDispatcherTimer dispatcherTimer;
private readonly IDispatcherTimerFactory dispatcherTimerFactory;
private readonly IDisposer disposer;
private readonly IPublisher publisher;
private readonly IServiceFactory serviceFactory;
private readonly Dictionary<string, TaskbarButton> taskbarButtons = [];
private readonly ITaskbarList taskbarList;
private Rect? taskbarRectCache;
private IUIAutomationCondition? taskListCondition;
private IUIAutomationElement? taskListElement;
private IntPtr taskListHandle;
public TaskbarButtonMonitor(ITaskbarList taskbarList,
IPublisher publisher,
IDispatcherTimerFactory dispatcherTimerFactory,
IServiceFactory serviceFactory,
IDisposer disposer)
{
this.taskbarList = taskbarList;
this.publisher = publisher;
this.dispatcherTimerFactory = dispatcherTimerFactory;
this.serviceFactory = serviceFactory;
this.disposer = disposer;
disposer.Add(this, dispatcherTimer = dispatcherTimerFactory.Create(OnDispatcher,
TimeSpan.FromMilliseconds(500)));
}
public void Dispose()
{
GC.SuppressFinalize(this);
disposer.Dispose(this);
}
public void Initialize()
{
CUIAutomation clientUIAutomation = new();
taskListCondition = clientUIAutomation.CreateTrueCondition();
taskListHandle = taskbarList.GetHandle();
taskListElement = clientUIAutomation.ElementFromHandle(taskListHandle);
if (WindowHelper.TryGetBounds(taskListHandle, out Rect? rect))
{
taskbarRectCache = rect;
}
dispatcherTimer.Start();
UpdateTaskbarButtons();
}
private bool CheckDirtyTaskbarRegion()
{
if (WindowHelper.TryGetBounds(taskListHandle, out Rect? rect))
{
if (taskbarRectCache?.Width != rect.Width ||
taskbarRectCache?.Height != rect.Height)
{
taskbarRectCache = rect;
return true;
}
}
return false;
}
private Dictionary<string, tagRECT> FindTaskbarButtons()
{
IUIAutomationElementArray? taskElements = taskListElement?.FindAll(TreeScope.TreeScope_Descendants |
TreeScope.TreeScope_Children, taskListCondition);
Dictionary<string, tagRECT> buttons = [];
if (taskElements is not null)
{
for (int index = 0; index <= taskElements.Length - 1; index++)
{
IUIAutomationElement taskUIElement = taskElements.GetElement(index);
string name = taskUIElement.CurrentName;
tagRECT rect = taskUIElement.CurrentBoundingRectangle;
buttons.Add(name, rect);
}
}
return buttons;
}
private void OnDispatcher()
{
dispatcherTimer.Stop();
if (CheckDirtyTaskbarRegion())
{
UpdateTaskbarButtons();
}
dispatcherTimer.Start();
}
private void UpdateTaskbarButtons()
{
if (taskListElement is null)
{
return;
}
Dictionary<string, tagRECT> buttons = FindTaskbarButtons();
foreach (KeyValuePair<string, TaskbarButton> buttonToRemove in taskbarButtons
.Where(taskbarButton => !buttons.ContainsKey(taskbarButton.Key)))
{
string key = buttonToRemove.Key;
TaskbarButton button = buttonToRemove.Value;
Debug.WriteLine($"{key} button removed");
taskbarButtons.Remove(key);
publisher.Publish(new TaskbarButtonRemovedEventArgs(button));
button.Dispose();
}
foreach (KeyValuePair<string, tagRECT> button in buttons)
{
string name = button.Key;
tagRECT bounds = button.Value;
Rect rect = new(bounds.left,
bounds.top,
bounds.right - bounds.left,
bounds.bottom - bounds.top);
if (taskbarButtons.TryGetValue(name, out TaskbarButton? taskbarButton))
{
Debug.WriteLine($"{name} button updated");
taskbarButtons[name].Rect = rect;
publisher.Publish(new TaskbarButtonUpdatedEventArgs(taskbarButtons[name]));
}
else
{
Debug.WriteLine($"{name} button added");
taskbarButtons.Add(name, serviceFactory.Create<TaskbarButton>(name, rect));
publisher.Publish(new TaskbarButtonCreatedEventArgs(taskbarButtons[name]));
}
}
}
}
@@ -0,0 +1,3 @@
namespace Toolkit.Windows;
public record TaskbarButtonRemovedEventArgs(TaskbarButton Button);
@@ -0,0 +1,3 @@
namespace Toolkit.Windows;
public record TaskbarButtonUpdatedEventArgs(TaskbarButton Button);
+21 -1
View File
@@ -8,7 +8,6 @@
<ResolveComReferenceSilent>True</ResolveComReferenceSilent>
<Platforms>AnyCPU;x64;x86</Platforms>
<WindowsSdkPackageVersion>10.0.19041.41</WindowsSdkPackageVersion>
</PropertyGroup>
<ItemGroup>
@@ -23,4 +22,25 @@
<ProjectReference Include="..\Toolkit.Foundation\Toolkit.Foundation.csproj" />
</ItemGroup>
<ItemGroup>
<COMReference Include="UIA">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>930299ce-9965-4dec-b0f4-a54848d4b667</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
<COMReference Include="UIAutomationClient">
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>944de083-8fb8-45cf-bcb7-c477acb2f897</Guid>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
</Project>
+2 -2
View File
@@ -9,7 +9,7 @@ public class WindowHelper
{
public static void BringToForeground(HWND handle)
{
if (TryGetBoundsUnsafe(handle, out var bounds))
if (TryGetBoundsUnsafe(handle, out RECT bounds))
{
PInvoke.SetWindowPos(handle, new HWND(), bounds.left, bounds.top, bounds.right -
bounds.left, bounds.bottom - bounds.top, SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE);
@@ -28,7 +28,7 @@ public class WindowHelper
public static bool TryGetBounds(IntPtr handle,
[MaybeNullWhen(false)] out Rect rect)
{
if (TryGetBoundsUnsafe(handle, out var unsafeRect))
if (TryGetBoundsUnsafe(handle, out RECT unsafeRect))
{
rect = new Rect(unsafeRect.left, unsafeRect.top, unsafeRect.right - unsafeRect.left, unsafeRect.bottom - unsafeRect.top);
+1 -1
View File
@@ -21,7 +21,7 @@ public class WndProcMonitor(IPublisher publisher) :
private unsafe void InitializeWndProc()
{
var windowName = Guid.NewGuid().ToString();
string windowName = Guid.NewGuid().ToString();
handler = Wndproc;
WNDCLASSW wndProcWindow;