2024-07-23 07:56:23 +02:00
|
|
|
using System;
|
|
|
|
using System.Threading;
|
|
|
|
using System.IO;
|
|
|
|
using IDE.util;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using Beefy.widgets;
|
|
|
|
|
|
|
|
namespace BeefCon;
|
|
|
|
|
|
|
|
class Program
|
|
|
|
{
|
|
|
|
BeefConConsoleProvider.Pipe mPipe ~ delete _;
|
|
|
|
WinNativeConsoleProvider mProvider ~ delete _;
|
|
|
|
int32 mPid;
|
2024-07-24 09:41:08 +02:00
|
|
|
int32 mAttachedPid;
|
|
|
|
Windows.ProcessHandle mAttachedProcess;
|
|
|
|
String mAttachedName = new .() ~ delete _;
|
2024-07-23 07:56:23 +02:00
|
|
|
int32 mConid;
|
|
|
|
String mExecStr = new .() ~ delete _;
|
|
|
|
SpawnedProcess mSpawnedProcess ~ delete _;
|
|
|
|
|
|
|
|
public ~this()
|
|
|
|
{
|
2024-07-24 09:41:08 +02:00
|
|
|
if (mSpawnedProcess != null)
|
|
|
|
{
|
|
|
|
mSpawnedProcess.Kill();
|
|
|
|
mSpawnedProcess.WaitFor();
|
|
|
|
}
|
2024-07-23 07:56:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static mixin GET<T>(var ptr)
|
|
|
|
{
|
|
|
|
*((T*)(ptr += sizeof(T)) - 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
public void MessageLoop()
|
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
switch (mPipe.ReadMessage(-1))
|
|
|
|
{
|
|
|
|
case .Ok(let msg):
|
|
|
|
uint8* ptr = msg.Ptr + 1;
|
|
|
|
switch (*(BeefConConsoleProvider.Message*)msg.Ptr)
|
|
|
|
{
|
|
|
|
case .GetData:
|
|
|
|
mPipe.StartMessage(BeefConConsoleProvider.Message.Data);
|
|
|
|
mPipe.Stream.Write((int32)mProvider.Width);
|
|
|
|
mPipe.Stream.Write((int32)mProvider.Height);
|
|
|
|
mPipe.Stream.Write((int32)mProvider.BufferHeight);
|
|
|
|
mPipe.Stream.Write((int32)mProvider.ScrollTop);
|
|
|
|
mPipe.Stream.Write(mProvider.CursorVisible);
|
|
|
|
mPipe.Stream.Write(mProvider.CursorHeight);
|
|
|
|
mPipe.Stream.Write(mProvider.CursorPos);
|
|
|
|
for (int i < 16)
|
|
|
|
mPipe.Stream.Write(mProvider.GetColor(i));
|
|
|
|
|
|
|
|
for (int row < mProvider.Height)
|
|
|
|
{
|
|
|
|
for (int col < mProvider.Width)
|
|
|
|
{
|
|
|
|
var cell = mProvider.GetCell(col, row);
|
|
|
|
mPipe.Stream.Write(cell.mChar);
|
|
|
|
mPipe.Stream.Write(cell.mAttributes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mPipe.EndMessage();
|
|
|
|
case .Resize:
|
|
|
|
int32 cols = GET!<int32>(ptr);
|
|
|
|
int32 rows = GET!<int32>(ptr);
|
|
|
|
bool resizeContent = GET!<bool>(ptr);
|
|
|
|
mProvider.Resize(cols, rows, resizeContent);
|
|
|
|
case .KeyDown:
|
|
|
|
KeyCode keyCode = GET!<KeyCode>(ptr);
|
|
|
|
KeyFlags keyFlags = GET!<KeyFlags>(ptr);
|
|
|
|
mProvider.KeyDown(keyCode, keyFlags);
|
|
|
|
case .KeyUp:
|
|
|
|
KeyCode keyCode = GET!<KeyCode>(ptr);
|
|
|
|
mProvider.KeyUp(keyCode);
|
|
|
|
case .InputString:
|
|
|
|
int32 strLen = GET!<int32>(ptr);
|
|
|
|
StringView str = .((.)ptr, strLen);
|
|
|
|
mProvider.SendInput(str);
|
|
|
|
case .MouseDown:
|
|
|
|
int32 col = GET!<int32>(ptr);
|
|
|
|
int32 row = GET!<int32>(ptr);
|
|
|
|
int32 btnState = GET!<int32>(ptr);
|
|
|
|
int32 btnCount = GET!<int32>(ptr);
|
|
|
|
KeyFlags keyFlags = GET!<KeyFlags>(ptr);
|
|
|
|
mProvider.MouseDown(col, row, btnState, btnCount, keyFlags);
|
|
|
|
case .MouseMove:
|
|
|
|
int32 col = GET!<int32>(ptr);
|
|
|
|
int32 row = GET!<int32>(ptr);
|
|
|
|
int32 btnState = GET!<int32>(ptr);
|
|
|
|
KeyFlags keyFlags = GET!<KeyFlags>(ptr);
|
|
|
|
mProvider.MouseMove(col, row, btnState, keyFlags);
|
|
|
|
case .MouseUp:
|
|
|
|
int32 col = GET!<int32>(ptr);
|
|
|
|
int32 row = GET!<int32>(ptr);
|
|
|
|
int32 btnState = GET!<int32>(ptr);
|
|
|
|
KeyFlags keyFlags = GET!<KeyFlags>(ptr);
|
|
|
|
mProvider.MouseUp(col, row, btnState, keyFlags);
|
|
|
|
case .MouseWheel:
|
|
|
|
int32 col = GET!<int32>(ptr);
|
|
|
|
int32 row = GET!<int32>(ptr);
|
|
|
|
int32 dy = GET!<int32>(ptr);
|
|
|
|
mProvider.MouseWheel(col, row, dy);
|
2024-07-23 15:13:53 +02:00
|
|
|
case .ScrollTo:
|
|
|
|
int32 row = GET!<int32>(ptr);
|
|
|
|
mProvider.ScrollTo(row);
|
|
|
|
case .Update:
|
|
|
|
bool paused = GET!<bool>(ptr);
|
|
|
|
mProvider.Update(paused);
|
2024-07-24 09:41:08 +02:00
|
|
|
case .Attached:
|
|
|
|
int32 pid = GET!<int32>(ptr);
|
|
|
|
Process process = scope .();
|
|
|
|
if (process.GetProcessById(pid) case .Ok)
|
|
|
|
{
|
|
|
|
mAttachedPid = pid;
|
|
|
|
mAttachedName.Set(process.ProcessName);
|
|
|
|
WinNativeConsoleProvider.SetConsoleTitleW(mAttachedName.ToScopedNativeWChar!());
|
|
|
|
mAttachedProcess = Windows.OpenProcess(Windows.PROCESS_ALL_ACCESS, false, mAttachedPid);
|
|
|
|
}
|
2024-07-23 07:56:23 +02:00
|
|
|
default:
|
|
|
|
}
|
|
|
|
case .Err(let err):
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-24 09:41:08 +02:00
|
|
|
public void ClearConsoleTitle()
|
|
|
|
{
|
|
|
|
WinNativeConsoleProvider.SetConsoleTitleW("BeefIDE Debug Console".ToScopedNativeWChar!());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*[CLink]
|
|
|
|
static extern void* freopen (char8 * filename, char8 * mode, void* stream );
|
|
|
|
[CLink]
|
|
|
|
static extern void* stdout;*/
|
|
|
|
|
2024-07-23 07:56:23 +02:00
|
|
|
public void Run()
|
|
|
|
{
|
|
|
|
mPipe = new .();
|
|
|
|
mPipe.Listen(mPid, mConid);
|
|
|
|
|
|
|
|
mProvider = new .();
|
2024-07-24 09:41:08 +02:00
|
|
|
mProvider.mHideNativeConsole = !mExecStr.IsEmpty;
|
2024-07-23 07:56:23 +02:00
|
|
|
mProvider.Attach();
|
2024-07-24 09:41:08 +02:00
|
|
|
Console.ReopenHandles();
|
2024-07-23 07:56:23 +02:00
|
|
|
|
2024-07-24 09:41:08 +02:00
|
|
|
if (!mExecStr.IsEmpty)
|
|
|
|
{
|
|
|
|
ProcessStartInfo procInfo = scope ProcessStartInfo();
|
|
|
|
procInfo.UseShellExecute = false;
|
|
|
|
procInfo.SetFileName(mExecStr);
|
2024-07-23 07:56:23 +02:00
|
|
|
|
2024-07-24 09:41:08 +02:00
|
|
|
mSpawnedProcess = new SpawnedProcess();
|
|
|
|
if (mSpawnedProcess.Start(procInfo) case .Err)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ClearConsoleTitle();
|
|
|
|
}
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
// Check BeefIDE process
|
|
|
|
{
|
|
|
|
var process = Platform.BfpProcess_GetById(null, mPid, null);
|
|
|
|
if (process == null)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Process closed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Platform.BfpProcess_Release(process);
|
|
|
|
}
|
|
|
|
|
|
|
|
MessageLoop();
|
|
|
|
|
|
|
|
if (mPipe.mFailed)
|
|
|
|
{
|
|
|
|
if (mSpawnedProcess == null)
|
|
|
|
{
|
|
|
|
DeleteAndNullify!(mPipe);
|
|
|
|
mPipe = new .();
|
|
|
|
mPipe.Listen(mPid, mConid);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mPipe.mConnected)
|
|
|
|
Thread.Sleep(20);
|
|
|
|
|
|
|
|
if (mSpawnedProcess != null)
|
|
|
|
{
|
|
|
|
if (mSpawnedProcess.WaitFor(0))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mAttachedPid != 0)
|
|
|
|
{
|
|
|
|
if ((Windows.GetExitCodeProcess(mAttachedProcess, var exitCode)) && (exitCode != 259))
|
|
|
|
{
|
|
|
|
ClearConsoleTitle();
|
|
|
|
|
|
|
|
Console.WriteLine();
|
|
|
|
Console.WriteLine(scope $"{mAttachedName} (process {mAttachedPid}) exited with code {exitCode}.");
|
|
|
|
Console.WriteLine("Press any key to close this window...");
|
|
|
|
|
|
|
|
mAttachedProcess.Close();
|
|
|
|
mAttachedProcess = default;
|
|
|
|
mAttachedPid = 0;
|
|
|
|
mAttachedName.Clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mSpawnedProcess == null) && (mAttachedPid == 0))
|
|
|
|
{
|
|
|
|
if (Console.KeyAvailable)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*public void RunHost()
|
|
|
|
{
|
|
|
|
mPipe = new .();
|
|
|
|
mPipe.Listen(mPid, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WinNativeConsoleProvider.AllocConsole();
|
|
|
|
WinNativeConsoleProvider.SetConsoleTitleW("BeefIDE Debug Console".ToScopedNativeWChar!());
|
2024-07-23 07:56:23 +02:00
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
var process = Platform.BfpProcess_GetById(null, mPid, null);
|
|
|
|
if (process == null)
|
|
|
|
{
|
|
|
|
Console.Error.WriteLine("Process closed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Platform.BfpProcess_Release(process);
|
|
|
|
MessageLoop();
|
|
|
|
|
|
|
|
if (mPipe.mFailed)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!mPipe.mConnected)
|
|
|
|
Thread.Sleep(20);
|
|
|
|
}
|
2024-07-24 09:41:08 +02:00
|
|
|
}*/
|
2024-07-23 07:56:23 +02:00
|
|
|
|
|
|
|
public static int Main(String[] args)
|
|
|
|
{
|
2024-07-24 09:41:08 +02:00
|
|
|
if (args.Count < 1)
|
2024-07-23 07:56:23 +02:00
|
|
|
{
|
2024-07-24 09:41:08 +02:00
|
|
|
Console.Error.WriteLine("Usage: BeefCon <pid> [conid] [exe]");
|
2024-07-23 07:56:23 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Program pg = scope .();
|
2024-07-24 09:41:08 +02:00
|
|
|
if (args.Count >= 3)
|
|
|
|
{
|
|
|
|
pg.mPid = int32.Parse(args[0]);
|
|
|
|
pg.mConid = int32.Parse(args[1]);
|
|
|
|
pg.mExecStr.Set(args[2]);
|
|
|
|
pg.Run();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pg.mPid = int32.Parse(args[0]);
|
|
|
|
pg.mConid = -Process.CurrentId;
|
|
|
|
pg.Run();
|
|
|
|
}
|
|
|
|
|
2024-07-23 07:56:23 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|