feat: Claude Code 原生 Windows 通知(C# / .NET 10 + Avalonia 12)
为 Claude Code 提供原生 Windows toast 通知:点击跳回原窗口、切回 Windows Terminal 标签、跨虚拟桌面、调用方图标、非阻塞投递;NativeAOT 单文件分发。
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
|
||||
namespace Notify.Interop;
|
||||
|
||||
/// <summary>
|
||||
/// 把目标窗口拉回前台
|
||||
///
|
||||
/// Windows 限制后台进程抢焦点,这里用一套组合技绕过:ALT 键模拟 +
|
||||
/// AttachThreadInput 把当前线程与前台/目标线程的输入队列挂接 +
|
||||
/// SetWindowPos/BringWindowToTop/SwitchToThisWindow/SetForegroundWindow 多管齐下
|
||||
/// </summary>
|
||||
public static class WindowActivator
|
||||
{
|
||||
public static bool Activate(IntPtr hwnd)
|
||||
{
|
||||
if (hwnd == IntPtr.Zero || !Win32.IsWindow(hwnd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 最小化的先还原
|
||||
if (Win32.IsIconic(hwnd))
|
||||
{
|
||||
Win32.ShowWindow(hwnd, Win32.SW_RESTORE);
|
||||
}
|
||||
|
||||
var foreground = Win32.GetForegroundWindow();
|
||||
var curThread = Win32.GetCurrentThreadId();
|
||||
var fgThread = Win32.GetWindowThreadProcessId(foreground, out _);
|
||||
var targetThread = Win32.GetWindowThreadProcessId(hwnd, out _);
|
||||
|
||||
// 模拟一次 ALT 抬起,满足 Windows 的"防焦点抢占"前置条件
|
||||
Win32.keybd_event(Win32.VK_MENU, 0, 0, IntPtr.Zero);
|
||||
Win32.keybd_event(Win32.VK_MENU, 0, Win32.KEYEVENTF_KEYUP, IntPtr.Zero);
|
||||
|
||||
if (fgThread != curThread)
|
||||
{
|
||||
Win32.AttachThreadInput(curThread, fgThread, true);
|
||||
}
|
||||
|
||||
if (targetThread != curThread && targetThread != fgThread)
|
||||
{
|
||||
Win32.AttachThreadInput(curThread, targetThread, true);
|
||||
}
|
||||
|
||||
Win32.AllowSetForegroundWindow(Win32.ASFW_ANY);
|
||||
Win32.SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, Win32.SWP_NOMOVE | Win32.SWP_NOSIZE | Win32.SWP_SHOWWINDOW);
|
||||
Win32.BringWindowToTop(hwnd);
|
||||
Win32.SwitchToThisWindow(hwnd, true);
|
||||
Win32.SetForegroundWindow(hwnd);
|
||||
Win32.ShowWindow(hwnd, Win32.SW_SHOW);
|
||||
|
||||
if (targetThread != curThread && targetThread != fgThread)
|
||||
{
|
||||
Win32.AttachThreadInput(curThread, targetThread, false);
|
||||
}
|
||||
|
||||
if (fgThread != curThread)
|
||||
{
|
||||
Win32.AttachThreadInput(curThread, fgThread, false);
|
||||
}
|
||||
|
||||
return Win32.GetForegroundWindow() == hwnd;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user