Added some terminal interrupt systems. Later it will kill active commands.

This commit is contained in:
That_One_Nerd 2023-03-31 18:12:20 -04:00
parent 51f58e6e82
commit 5412b023a0
4 changed files with 90 additions and 6 deletions

View File

@ -3,6 +3,7 @@ global using SharpCompress.Archives.Rar;
global using SharpCompress.Archives.SevenZip; global using SharpCompress.Archives.SevenZip;
global using SharpCompress.Readers; global using SharpCompress.Readers;
global using SrcMod.Shell; global using SrcMod.Shell;
global using SrcMod.Shell.Interop;
global using SrcMod.Shell.Modules.ObjectModels; global using SrcMod.Shell.Modules.ObjectModels;
global using System; global using System;
global using System.Collections.Generic; global using System.Collections.Generic;

View File

@ -0,0 +1,25 @@
namespace SrcMod.Shell.Interop;
internal static partial class Winmm
{
[LibraryImport("winmm.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool PlaySound([MarshalAs(UnmanagedType.LPStr)] string pszSound, nint hMod, uint fdwSound);
public enum PlaySoundFlags : uint
{
SND_SYNC = 0x00000000,
SND_ASYNC = 0x00000001,
SND_NODEFAULT = 0x00000002,
SND_MEMORY = 0x00000004,
SND_LOOP = 0x00000008,
SND_NOSTOP = 0x00000010,
SND_PURGE = 0x00000040,
SND_APPLICATION = 0x00000080,
SND_NOWAIT = 0x00002000,
SND_ALIAS = 0x00010000,
SND_FILENAME = 0x00020000,
SND_RESOURCE = 0x00040000,
SND_ALIAS_ID = 0x00100000,
}
}

View File

@ -1,6 +1,4 @@
using SrcMod.Shell.Interop; namespace SrcMod.Shell.Modules;
namespace SrcMod.Shell.Modules;
[Module("clipboard")] [Module("clipboard")]
public static class ClipboardModule public static class ClipboardModule

View File

@ -16,6 +16,9 @@ public class Shell
public List<HistoryItem> History; public List<HistoryItem> History;
public string WorkingDirectory; public string WorkingDirectory;
private bool lastCancel;
private bool printedCancel;
public Shell() public Shell()
{ {
Console.CursorVisible = false; Console.CursorVisible = false;
@ -79,6 +82,9 @@ public class Shell
Write(" by ", ConsoleColor.White, false); Write(" by ", ConsoleColor.White, false);
Write($"{Author}", ConsoleColor.DarkYellow); Write($"{Author}", ConsoleColor.DarkYellow);
lastCancel = false;
Console.CancelKeyPress += HandleCancel;
ActiveGame = null; ActiveGame = null;
ReloadDirectoryInfo(); ReloadDirectoryInfo();
@ -106,8 +112,6 @@ public class Shell
public string ReadLine() public string ReadLine()
{ {
Console.CursorVisible = true;
Write($"\n{WorkingDirectory}", ConsoleColor.DarkGreen, false); Write($"\n{WorkingDirectory}", ConsoleColor.DarkGreen, false);
if (ActiveGame is not null) Write($" {ActiveGame}", ConsoleColor.DarkYellow, false); if (ActiveGame is not null) Write($" {ActiveGame}", ConsoleColor.DarkYellow, false);
if (ActiveMod is not null) Write($" {ActiveMod}", ConsoleColor.Magenta, false); if (ActiveMod is not null) Write($" {ActiveMod}", ConsoleColor.Magenta, false);
@ -116,17 +120,55 @@ public class Shell
Write($" {Name}", ConsoleColor.DarkCyan, false); Write($" {Name}", ConsoleColor.DarkCyan, false);
Write(" > ", ConsoleColor.White, false); Write(" > ", ConsoleColor.White, false);
bool printed = false;
if (lastCancel && !printedCancel)
{
// Print the warning. A little bit of mess because execution must
// continue without funny printing errors but it's alright I guess.
int originalLeft = Console.CursorLeft;
Console.CursorTop -= 3;
Write("Press ^C again to exit the shell.", ConsoleColor.Red);
// Send a warning sound.
Winmm.PlaySound("SystemAsterisk", nint.Zero,
(uint)(Winmm.PlaySoundFlags.SND_ALIAS | Winmm.PlaySoundFlags.SND_ASYNC));
printedCancel = true;
Console.CursorTop += 2;
Console.CursorLeft = originalLeft;
printed = true;
}
Console.ForegroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.White;
Console.CursorVisible = true;
string message = Console.ReadLine()!; string message = Console.ReadLine()!;
Console.CursorVisible = false;
Console.ResetColor(); Console.ResetColor();
Console.CursorVisible = false; if (!printed)
{
lastCancel = false;
printedCancel = false;
}
return message; return message;
} }
public void InvokeCommand(string cmd) public void InvokeCommand(string cmd)
{ {
if (cmd is null)
{
// This usually won't happen, but might if for example
// the shell cancel interrupt is called. This probably
// happens for other shell interrupts are called.
Write(null);
return;
}
List<string> parts = new(); List<string> parts = new();
string active = string.Empty; string active = string.Empty;
@ -205,4 +247,22 @@ public class Shell
if (ActiveMod is not null) title += $" - {ActiveMod.Name}"; if (ActiveMod is not null) title += $" - {ActiveMod.Name}";
Console.Title = title; Console.Title = title;
} }
private void HandleCancel(object? sender, ConsoleCancelEventArgs args)
{
// Due to some funny multithreading issues, we want to make the warning label
// single-threaded on the shell.
if (!lastCancel)
{
// Enable the warning. The "ReadLine" method will do the rest.
lastCancel = true;
args.Cancel = true; // "Cancel" referring to the cancellation of the cancel operation.
return;
}
// Actually kill the shell. We do still have to worry about some multithreaded
// nonsense, but a bearable amount of it.
Console.ResetColor();
Environment.Exit(0);
}
} }