Files
KianaBH3/Common/Util/IConsole.cs
2025-06-14 11:15:32 +08:00

185 lines
5.5 KiB
C#

using Kodnix.Character;
namespace KianaBH.Util;
public class IConsole
{
public static readonly string PrefixContent = "[KianaBH]> ";
public static readonly string Prefix = $"\u001b[38;2;255;192;203m{PrefixContent}\u001b[0m";
private static readonly int HistoryMaxCount = 10;
public static List<char> Input { get; set; } = [];
private static int CursorIndex { get; set; } = 0;
private static readonly List<string> InputHistory = [];
private static int HistoryIndex = -1;
public static event Action<string>? OnConsoleExcuteCommand;
public static void InitConsole()
{
Console.Title = ConfigManager.Config.GameServer.GameServerName;
}
public static int GetWidth(string str)
=> str.ToCharArray().Sum(EastAsianWidth.GetLength);
public static void RedrawInput(List<char> input, bool hasPrefix = true)
=> RedrawInput(new string([.. input]), hasPrefix);
public static void RedrawInput(string input, bool hasPrefix = true)
{
var length = GetWidth(input);
if (hasPrefix)
{
input = Prefix + input;
length += GetWidth(PrefixContent);
}
if (Console.GetCursorPosition().Left > 0)
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write(input + new string(' ', Console.BufferWidth - length));
Console.SetCursorPosition(length, Console.CursorTop);
}
#region Handlers
public static void HandleEnter()
{
var input = new string([.. Input]);
if (string.IsNullOrWhiteSpace(input)) return;
// New line
Console.WriteLine();
Input = [];
CursorIndex = 0;
if (InputHistory.Count >= HistoryMaxCount)
InputHistory.RemoveAt(0);
InputHistory.Add(input);
HistoryIndex = InputHistory.Count;
// Handle command
if (input.StartsWith('/')) input = input[1..].Trim();
OnConsoleExcuteCommand?.Invoke(input);
}
public static void HandleBackspace()
{
if (CursorIndex <= 0) return;
CursorIndex--;
var targetWidth = GetWidth(Input[CursorIndex].ToString());
Input.RemoveAt(CursorIndex);
var (left, _) = Console.GetCursorPosition();
Console.SetCursorPosition(left - targetWidth, Console.CursorTop);
var remain = new string([.. Input.Skip(CursorIndex)]);
Console.Write(remain + new string(' ', targetWidth));
Console.SetCursorPosition(left - targetWidth, Console.CursorTop);
}
public static void HandleUpArrow()
{
if (InputHistory.Count == 0) return;
if (HistoryIndex > 0)
{
HistoryIndex--;
var history = InputHistory[HistoryIndex];
Input = [.. history];
CursorIndex = Input.Count;
RedrawInput(Input);
}
}
public static void HandleDownArrow()
{
if (HistoryIndex >= InputHistory.Count) return;
HistoryIndex++;
if (HistoryIndex >= InputHistory.Count)
{
HistoryIndex = InputHistory.Count;
Input = [];
CursorIndex = 0;
}
else
{
var history = InputHistory[HistoryIndex];
Input = [.. history];
CursorIndex = Input.Count;
}
RedrawInput(Input);
}
public static void HandleLeftArrow()
{
if (CursorIndex <= 0) return;
var (left, _) = Console.GetCursorPosition();
CursorIndex--;
Console.SetCursorPosition(left - GetWidth(Input[CursorIndex].ToString()), Console.CursorTop);
}
public static void HandleRightArrow()
{
if (CursorIndex >= Input.Count) return;
var (left, _) = Console.GetCursorPosition();
CursorIndex++;
Console.SetCursorPosition(left + GetWidth(Input[CursorIndex - 1].ToString()), Console.CursorTop);
}
public static void HandleInput(ConsoleKeyInfo keyInfo)
{
if (char.IsControl(keyInfo.KeyChar)) return;
if (Input.Count >= (Console.BufferWidth - PrefixContent.Length)) return;
HandleInput(keyInfo.KeyChar);
}
public static void HandleInput(char keyChar)
{
Input.Insert(CursorIndex, keyChar);
CursorIndex++;
var (left, _) = Console.GetCursorPosition();
Console.Write(new string([.. Input.Skip(CursorIndex - 1)]));
Console.SetCursorPosition(left + GetWidth(keyChar.ToString()), Console.CursorTop);
}
#endregion
public static string ListenConsole()
{
while (true)
{
ConsoleKeyInfo keyInfo;
try { keyInfo = Console.ReadKey(true); }
catch (InvalidOperationException) { continue; }
switch (keyInfo.Key)
{
case ConsoleKey.Enter:
HandleEnter();
break;
case ConsoleKey.Backspace:
HandleBackspace();
break;
case ConsoleKey.LeftArrow:
HandleLeftArrow();
break;
case ConsoleKey.RightArrow:
HandleRightArrow();
break;
case ConsoleKey.UpArrow:
HandleUpArrow();
break;
case ConsoleKey.DownArrow:
HandleDownArrow();
break;
default:
HandleInput(keyInfo);
break;
}
}
}
}