Files
AX-Copilot-Codex/.decompiledproj/AxCopilot/Core/SnippetExpander.cs

265 lines
5.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using AxCopilot.Models;
using AxCopilot.Services;
namespace AxCopilot.Core;
public class SnippetExpander
{
private struct INPUT
{
public int type;
public InputUnion u;
}
[StructLayout(LayoutKind.Explicit)]
private struct InputUnion
{
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
private struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public nint dwExtraInfo;
}
private struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public nint dwExtraInfo;
}
private struct HARDWAREINPUT
{
public uint uMsg;
public ushort wParamL;
public ushort wParamH;
}
private readonly SettingsService _settings;
private readonly StringBuilder _buffer = new StringBuilder();
private bool _tracking;
private const ushort VK_BACK = 8;
private const int VK_ESCAPE = 27;
private const int VK_SPACE = 32;
private const int VK_RETURN = 13;
private const int VK_OEM_1 = 186;
private const int VK_SHIFT = 16;
private const int VK_CONTROL = 17;
private const int VK_MENU = 18;
private const ushort VK_CTRL_US = 17;
private static readonly HashSet<int> ClearKeys = new HashSet<int> { 33, 34, 35, 36, 37, 38, 39, 40, 46 };
public SnippetExpander(SettingsService settings)
{
_settings = settings;
}
public bool HandleKey(int vkCode)
{
if (!_settings.Settings.Launcher.SnippetAutoExpand)
{
return false;
}
if ((GetAsyncKeyState(17) & 0x8000) != 0)
{
_tracking = false;
_buffer.Clear();
return false;
}
if ((GetAsyncKeyState(18) & 0x8000) != 0)
{
_tracking = false;
_buffer.Clear();
return false;
}
if (vkCode == 186 && (GetAsyncKeyState(16) & 0x8000) == 0)
{
_tracking = true;
_buffer.Clear();
_buffer.Append(';');
return false;
}
if (!_tracking)
{
return false;
}
if ((vkCode >= 65 && vkCode <= 90) || (vkCode >= 48 && vkCode <= 57) || (vkCode >= 96 && vkCode <= 105) || vkCode == 189)
{
bool shifted = (GetAsyncKeyState(16) & 0x8000) != 0;
char c = VkToChar(vkCode, shifted);
if (c != 0)
{
_buffer.Append(char.ToLowerInvariant(c));
}
return false;
}
switch (vkCode)
{
case 8:
if (_buffer.Length > 1)
{
_buffer.Remove(_buffer.Length - 1, 1);
}
else
{
_tracking = false;
_buffer.Clear();
}
return false;
default:
if (vkCode != 13)
{
if (vkCode == 27 || ClearKeys.Contains(vkCode) || vkCode >= 112)
{
_tracking = false;
_buffer.Clear();
}
return false;
}
goto case 32;
case 32:
if (_buffer.Length > 1)
{
string keyword = _buffer.ToString(1, _buffer.Length - 1);
_tracking = false;
_buffer.Clear();
SnippetEntry snippetEntry = _settings.Settings.Snippets.FirstOrDefault((SnippetEntry s) => s.Key.Equals(keyword, StringComparison.OrdinalIgnoreCase));
if (snippetEntry != null)
{
string expanded = ExpandVariables(snippetEntry.Content);
int deleteCount = keyword.Length + 1;
((DispatcherObject)Application.Current).Dispatcher.BeginInvoke((Delegate)(Action)delegate
{
PasteExpansion(expanded, deleteCount);
}, Array.Empty<object>());
return true;
}
}
_tracking = false;
_buffer.Clear();
return false;
}
}
private static void PasteExpansion(string text, int deleteCount)
{
try
{
INPUT[] array = new INPUT[deleteCount * 2];
for (int i = 0; i < deleteCount; i++)
{
array[i * 2] = MakeKeyInput(8, keyUp: false);
array[i * 2 + 1] = MakeKeyInput(8, keyUp: true);
}
SendInput((uint)array.Length, array, Marshal.SizeOf<INPUT>());
Clipboard.SetText(text);
INPUT[] array2 = new INPUT[4]
{
MakeKeyInput(17, keyUp: false),
MakeKeyInput(86, keyUp: false),
MakeKeyInput(86, keyUp: true),
MakeKeyInput(17, keyUp: true)
};
SendInput((uint)array2.Length, array2, Marshal.SizeOf<INPUT>());
LogService.Info($"스니펫 확장 완료: {deleteCount}자 삭제 후 붙여넣기");
}
catch (Exception ex)
{
LogService.Warn("스니펫 확장 실패: " + ex.Message);
}
}
private static INPUT MakeKeyInput(ushort vk, bool keyUp)
{
INPUT result = new INPUT
{
type = 1
};
result.u.ki.wVk = vk;
result.u.ki.dwFlags = (keyUp ? 2u : 0u);
return result;
}
private static string ExpandVariables(string content)
{
DateTime now = DateTime.Now;
return content.Replace("{date}", now.ToString("yyyy-MM-dd")).Replace("{time}", now.ToString("HH:mm:ss")).Replace("{datetime}", now.ToString("yyyy-MM-dd HH:mm:ss"))
.Replace("{year}", now.Year.ToString())
.Replace("{month}", now.Month.ToString("D2"))
.Replace("{day}", now.Day.ToString("D2"));
}
private static char VkToChar(int vk, bool shifted)
{
if (vk >= 65 && vk <= 90)
{
return shifted ? ((char)vk) : char.ToLowerInvariant((char)vk);
}
if (vk >= 48 && vk <= 57)
{
return shifted ? ")!@#$%^&*("[vk - 48] : ((char)vk);
}
if (vk >= 96 && vk <= 105)
{
return (char)(48 + (vk - 96));
}
if (vk == 189)
{
return shifted ? '_' : '-';
}
return '\0';
}
[DllImport("user32.dll")]
private static extern short GetAsyncKeyState(int vKey);
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
}