143 lines
4.2 KiB
C#
143 lines
4.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using AxCopilot.SDK;
|
|
|
|
namespace AxCopilot.Handlers;
|
|
|
|
public class WindowSwitchHandler : IActionHandler
|
|
{
|
|
private delegate bool EnumWindowsProc(nint hWnd, nint lParam);
|
|
|
|
private record WindowInfo(nint Handle, string Title, string ProcessName, bool IsMinimized);
|
|
|
|
private const int SW_RESTORE = 9;
|
|
|
|
public string? Prefix => "win";
|
|
|
|
public PluginMetadata Metadata => new PluginMetadata("WindowSwitch", "윈도우 포커스 스위처 — win", "1.0", "AX");
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, nint lParam);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool IsWindowVisible(nint hWnd);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern int GetWindowTextLength(nint hWnd);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern int GetWindowText(nint hWnd, StringBuilder lpString, int nMaxCount);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern uint GetWindowThreadProcessId(nint hWnd, out uint lpdwProcessId);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool SetForegroundWindow(nint hWnd);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool ShowWindow(nint hWnd, int nCmdShow);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool IsIconic(nint hWnd);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern nint GetShellWindow();
|
|
|
|
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
|
{
|
|
string q = query.Trim();
|
|
List<WindowInfo> list = GetOpenWindows();
|
|
if (!string.IsNullOrWhiteSpace(q))
|
|
{
|
|
list = list.Where((WindowInfo w) => w.Title.Contains(q, StringComparison.OrdinalIgnoreCase) || w.ProcessName.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();
|
|
}
|
|
if (!list.Any())
|
|
{
|
|
return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem(string.IsNullOrWhiteSpace(q) ? "열린 창이 없습니다" : ("'" + q + "'에 해당하는 창 없음"), "win 뒤에 프로세스명 또는 창 제목 입력", null, null, null, "\ue946")));
|
|
}
|
|
List<LauncherItem> list2 = (from w in list.Take(15)
|
|
select new LauncherItem((w.Title.Length > 60) ? (w.Title.Substring(0, 57) + "…") : w.Title, w.ProcessName + " · " + (w.IsMinimized ? "[최소화됨] · " : "") + "Enter → 전환", null, w.Handle, null, "\ue7f4")).ToList();
|
|
list2.Insert(0, new LauncherItem($"열린 창 {list.Count}개", "Enter → 해당 창으로 즉시 전환", null, null, null, "\ue946"));
|
|
return Task.FromResult((IEnumerable<LauncherItem>)list2);
|
|
}
|
|
|
|
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
|
{
|
|
if (item.Data is nint num && num != IntPtr.Zero)
|
|
{
|
|
if (IsIconic(num))
|
|
{
|
|
ShowWindow(num, 9);
|
|
}
|
|
SetForegroundWindow(num);
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private static List<WindowInfo> GetOpenWindows()
|
|
{
|
|
List<WindowInfo> list = new List<WindowInfo>();
|
|
nint shellWnd = GetShellWindow();
|
|
string currentProcessName = Process.GetCurrentProcess().ProcessName;
|
|
EnumWindows(delegate(nint hWnd, nint _)
|
|
{
|
|
if (hWnd == shellWnd)
|
|
{
|
|
return true;
|
|
}
|
|
if (!IsWindowVisible(hWnd))
|
|
{
|
|
return true;
|
|
}
|
|
int windowTextLength = GetWindowTextLength(hWnd);
|
|
if (windowTextLength == 0)
|
|
{
|
|
return true;
|
|
}
|
|
StringBuilder stringBuilder = new StringBuilder(windowTextLength + 1);
|
|
GetWindowText(hWnd, stringBuilder, stringBuilder.Capacity);
|
|
string title = stringBuilder.ToString();
|
|
string text = "";
|
|
try
|
|
{
|
|
GetWindowThreadProcessId(hWnd, out var lpdwProcessId);
|
|
text = Process.GetProcessById((int)lpdwProcessId).ProcessName;
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
if (text == currentProcessName)
|
|
{
|
|
return true;
|
|
}
|
|
bool flag;
|
|
switch (text)
|
|
{
|
|
case "ApplicationFrameHost":
|
|
case "ShellExperienceHost":
|
|
case "SearchHost":
|
|
case "StartMenuExperienceHost":
|
|
case "TextInputHost":
|
|
flag = true;
|
|
break;
|
|
default:
|
|
flag = false;
|
|
break;
|
|
}
|
|
if (flag)
|
|
{
|
|
return true;
|
|
}
|
|
list.Add(new WindowInfo(hWnd, title, text, IsIconic(hWnd)));
|
|
return true;
|
|
}, IntPtr.Zero);
|
|
return list;
|
|
}
|
|
}
|