1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-17 23:56:05 +02:00
Beef/IDE/src/ui/ConsolePanel.bf

1031 lines
31 KiB
Beef
Raw Normal View History

2024-07-19 10:31:33 +02:00
#pragma warning disable 168
using System;
using Beefy.geom;
using Beefy.gfx;
using System.Text;
using Beefy.theme.dark;
using System.Security.Cryptography;
using Beefy.widgets;
using Beefy.events;
using System.Diagnostics;
using Beefy.utils;
using System.Threading;
namespace IDE.ui;
class ConsolePanel : Panel
{
[CRepr]
struct CONSOLE_SCREEN_BUFFER_INFOEX
{
public uint32 mSize;
public int16 mWidth;
public int16 mHeight;
public uint16 mCursorX;
public uint16 mCursorY;
public uint16 wAttributes;
public RECT mWindowRect;
public POINT mMaximumWindowSize;
public uint16 mPopupAttributes;
public Windows.IntBool mFullscreenSupported;
public uint32[16] mColorTable;
public this()
{
this = default;
mSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
}
}
[CRepr]
struct POINT : this(int16 x, int16 y)
{
}
[CRepr]
struct RECT : this(int16 left, int16 top, int16 right, int16 bottom)
{
public int16 Width => right - left;
public int16 Height => bottom - top;
}
[CRepr]
struct CHAR_INFO
{
public char16 mChar;
public uint16 mAttributes;
}
[CRepr]
struct CONSOLE_FONT_INFO
{
public uint32 mNumFont;
public POINT mSize;
}
[CRepr]
struct CONSOLE_CURSOR_INFO
{
public uint32 mSize;
public uint32 mVisible;
}
[CRepr]
struct CONSOLE_SELECTION_INFO
{
public uint32 mFlags;
public POINT mSelectionAnchor;
public RECT mSelection;
}
[CRepr]
struct KEY_EVENT_RECORD
{
public int32 mKeyDown;
public uint16 mRepeatCount;
public uint16 mVirtualKeyCode;
public uint16 mVirtualScanCode;
public char16 mChar;
public uint32 mControlKeyState;
}
[CRepr]
struct MOUSE_EVENT_RECORD
{
public POINT mMousePosition;
public uint32 mButtonState;
public uint32 mControlKeyState;
public uint32 mEventFlags;
}
[CRepr]
struct INPUT_RECORD
{
public uint16 mEventType;
public INPUT_RECORD_DATA mEventData;
}
[Union]
struct INPUT_RECORD_DATA
{
public KEY_EVENT_RECORD mKeyEvent;
public MOUSE_EVENT_RECORD mMouseEvent;
}
#if BF_PLATFORM_WINDOWS
[CLink, CallingConvention(.Stdcall)]
public static extern void AllocConsole();
[CLink, CallingConvention(.Stdcall)]
public static extern void AttachConsole(int processId);
[CLink, CallingConvention(.Stdcall)]
public static extern void FreeConsole();
[CLink, CallingConvention(.Stdcall)]
public static extern Windows.IntBool GetConsoleScreenBufferInfoEx(Windows.Handle handle, ref CONSOLE_SCREEN_BUFFER_INFOEX info);
[CLink, CallingConvention(.Stdcall)]
public static extern Windows.IntBool SetConsoleScreenBufferInfoEx(Windows.Handle handle, ref CONSOLE_SCREEN_BUFFER_INFOEX info);
[CLink]
public static extern Windows.IntBool ReadConsoleOutputW(Windows.Handle handle, void* buffer, POINT bufferSize, POINT bufferCoord, ref RECT readRegion);
[CLink]
public static extern Windows.IntBool SetConsoleScreenBufferSize(Windows.Handle handle, POINT bufferSize);
[CLink]
public static extern Windows.IntBool SetConsoleWindowInfo(Windows.Handle handle, Windows.IntBool absolute, in RECT window);
[CLink]
public static extern Windows.HWnd GetConsoleWindow();
[CLink]
public static extern Windows.IntBool GetCurrentConsoleFont(Windows.Handle handle, Windows.IntBool maxWindow, out CONSOLE_FONT_INFO fontInfo);
[CLink]
public static extern Windows.IntBool GetConsoleCursorInfo(Windows.Handle handle, out CONSOLE_CURSOR_INFO cursorInfo);
[CLink]
public static extern Windows.IntBool GetConsoleSelectionInfo(out CONSOLE_SELECTION_INFO selectionInfo);
[CLink]
public static extern Windows.IntBool WriteConsoleInputW(Windows.Handle handle, INPUT_RECORD* eventsPtr, int32 eventCount, out int32 numEventsWritten);
[CLink]
public static extern Windows.IntBool ReadConsoleInputW(Windows.Handle handle, INPUT_RECORD* eventsPtr, int32 eventCount, out int32 numEventsRead);
#endif
class View : Widget
{
public ConsolePanel mConsolePanel;
public this(ConsolePanel ConsolePanel)
{
mConsolePanel = ConsolePanel;
}
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
{
base.MouseDown(x, y, btn, btnCount);
var inHandle = Console.[Friend]GetStdHandle(Console.STD_INPUT_HANDLE);
if (mConsolePanel.mMousePassThrough)
{
var cell = mConsolePanel.GetCell(x, y);
INPUT_RECORD input = default;
input.mEventType = 2 /*MOUSE_EVENT */;
input.mEventData.mMouseEvent.mButtonState = (.)mMouseFlags;
if (btnCount > 1)
input.mEventData.mMouseEvent.mEventFlags |= 2;
input.mEventData.mMouseEvent.mMousePosition = .((.)cell.mX, (.)cell.mY);
input.mEventData.mMouseEvent.mControlKeyState = mConsolePanel.GetControlKeyState(mWidgetWindow.GetKeyFlags(false));
WriteConsoleInputW(inHandle, &input, 1, var numEVentsWritten);
}
else
{
if (btn == 0)
{
}
else if (btn == 1)
{
var text = gApp.GetClipboardText(.. scope .());
for (var c in text.DecodedChars)
{
INPUT_RECORD input = default;
input.mEventType = 1 /*KEY_EVENT */;
input.mEventData.mKeyEvent.mKeyDown = 1;
input.mEventData.mKeyEvent.mRepeatCount = 1;
//input.mEventData.mKeyEvent.mVirtualKeyCode = (.)keyEvent.mKeyCode;
//input.mEventData.mKeyEvent.mVirtualScanCode = 61;
//input.mEventData.mKeyEvent.mControlKeyState = GetControlKeyState(keyEvent.mKeyFlags);
input.mEventData.mKeyEvent.mChar = (.)c;
WriteConsoleInputW(inHandle, &input, 1, var numEVentsWritten);
}
}
}
/*int flags = (.)mMouseFlags;
var window = GetConsoleWindow();
//Windows.SendMessageW(window, 0x0006, 0, 0);
Windows.SendMessageW(window, 0x0007, 0, 0);
//Windows.SetActiveWindow(window);
//Windows.SetFocus(window);
if (btn == 0)
Windows.SendMessageW(window, 0x0201 /*WM_LBUTTONDOWN*/, flags, (int)x | ((int)y << 16));
else if (btn == 1)
{
Windows.SendMessageW(window, 0x0204 /*WM_RBUTTONDOWN*/, flags, (int)x | ((int)y << 16));
//Windows.SendMessageW(window, 0x0100, 0, 0);
}*/
}
public override void MouseMove(float x, float y)
{
base.MouseMove(x, y);
var inHandle = Console.[Friend]GetStdHandle(Console.STD_INPUT_HANDLE);
var cell = mConsolePanel.GetCell(x, y);
INPUT_RECORD input = default;
input.mEventType = 2 /*MOUSE_EVENT */;
input.mEventData.mMouseEvent.mButtonState = (.)mMouseFlags;
input.mEventData.mMouseEvent.mEventFlags |= 1; /* MOUSE_MOVED */
input.mEventData.mMouseEvent.mMousePosition = .((.)cell.mX, (.)cell.mY);
input.mEventData.mMouseEvent.mControlKeyState = mConsolePanel.GetControlKeyState(mWidgetWindow.GetKeyFlags(false));
WriteConsoleInputW(inHandle, &input, 1, var numEVentsWritten);
/*var window = GetConsoleWindow();
Windows.SendMessageW(window, 0x0200 /*WM_MOUSEMOVE*/, 0, (int)x | ((int)y << 16));*/
}
public override void MouseUp(float x, float y, int32 btn)
{
base.MouseUp(x, y, btn);
var inHandle = Console.[Friend]GetStdHandle(Console.STD_INPUT_HANDLE);
var cell = mConsolePanel.GetCell(x, y);
INPUT_RECORD input = default;
input.mEventType = 2 /*MOUSE_EVENT */;
input.mEventData.mMouseEvent.mButtonState = (.)mMouseFlags;
//input.mEventData.mMouseEvent.mEventFlags |= 1; /* MOUSE_MOVED */
input.mEventData.mMouseEvent.mMousePosition = .((.)cell.mX, (.)cell.mY);
input.mEventData.mMouseEvent.mControlKeyState = mConsolePanel.GetControlKeyState(mWidgetWindow.GetKeyFlags(false));
WriteConsoleInputW(inHandle, &input, 1, var numEVentsWritten);
/*var window = GetConsoleWindow();
Windows.SendMessageW(window, 0x0202 /*WM_LBUTTONUP*/, 0, (int)x | ((int)y << 16));*/
}
public override void KeyDown(KeyDownEvent keyEvent)
{
base.KeyDown(keyEvent);
if (keyEvent.mKeyCode == .Insert)
{
ProcessStartInfo procInfo = scope ProcessStartInfo();
procInfo.UseShellExecute = false;
procInfo.SetFileName("Powershell.exe");
String resultStr = scope String();
var spawn = scope SpawnedProcess();
spawn.Start(procInfo);
}
if (keyEvent.mKeyCode == .Tilde)
{
if (mConsolePanel.mHasConsole)
{
mConsolePanel.Detach();
}
else
{
mConsolePanel.Attach();
ProcessStartInfo procInfo = scope ProcessStartInfo();
procInfo.UseShellExecute = false;
procInfo.SetFileName("Powershell.exe");
String resultStr = scope String();
mConsolePanel.mExecSpawn = new SpawnedProcess();
mConsolePanel.mExecSpawn.Start(procInfo);
}
}
}
public override void KeyUp(KeyCode keyCode)
{
base.KeyUp(keyCode);
}
public override void GotFocus()
{
base.GotFocus();
mConsolePanel.mCursorBlinkTicks = 0;
}
public override void MouseWheel(MouseEvent evt)
{
if ((mConsolePanel.mPaused) || (mConsolePanel.mHasConsole))
{
base.MouseWheel(evt);
return;
}
/*var inHandle = Console.[Friend]GetStdHandle(Console.STD_INPUT_HANDLE);
var cell = mConsolePanel.GetCell(evt.mX, evt.mY);
INPUT_RECORD input = default;
input.mEventType = 2 /*MOUSE_EVENT */;
input.mEventData.mMouseEvent.mButtonState = (.)((int32)mMouseFlags | ((int32)evt.mWheelDeltaY << 16));
input.mEventData.mMouseEvent.mEventFlags |= 4 /* MOUSE_WHEELED */;
input.mEventData.mMouseEvent.mMousePosition = .((.)cell.mX, (.)cell.mY);
input.mEventData.mMouseEvent.mControlKeyState = mConsolePanel.GetControlKeyState(mWidgetWindow.GetKeyFlags());
WriteConsoleInputW(inHandle, &input, 1, var numEVentsWritten);*/
float x = evt.mX;
float y = evt.mY;
var window = GetConsoleWindow();
Windows.SendMessageW(window, 0x0007, 0, 0); // WM_SETFOCUS
//Windows.SendMessageW(window, 0x0006, 0, 0); // WM_ACTIVATE
Windows.SendMessageW(window, 0x0200 /*WM_MOUSEMOVE*/, 0, (int)x | ((int)y << 16));
Windows.SendMessageW(window, 0x020A /*WM_MOUSEWHEEL*/, (int32)(120 * evt.mWheelDeltaY) << 16, (int)x | ((int)y << 16));
}
}
class ScreenInfo
{
public CONSOLE_SCREEN_BUFFER_INFOEX mInfo;
public CONSOLE_CURSOR_INFO mCursorInfo;
public CONSOLE_SELECTION_INFO mSelectionInfo;
public int32 mScrollTop;
public CHAR_INFO* mCharInfo;
public CHAR_INFO* mFullCharInfo;
public int32 WindowWidth => mInfo.mWindowRect.Width;
public int32 WindowHeight => mInfo.mWindowRect.Height;
public ~this()
{
delete mCharInfo;
delete mFullCharInfo;
}
public int GetHashCode()
{
MD5 md5 = scope .();
md5.Update(.((.)&mInfo, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX)));
md5.Update(.((.)&mSelectionInfo, sizeof(CONSOLE_SELECTION_INFO)));
md5.Update(.((.)&mCursorInfo, sizeof(CONSOLE_CURSOR_INFO)));
md5.Update(.((.)mCharInfo, (int32)mInfo.mWindowRect.Width * mInfo.mWindowRect.Height * sizeof(CHAR_INFO)));
var hash = md5.Finish();
return hash.GetHashCode();
}
}
public int mLastDrawnHashCode;
public DarkScrollbar mScrollbar;
public ScrollableWidget mScrollableWidget;
public int32 mCellWidth;
public int32 mCellHeight;
public bool mPaused;
ScreenInfo mScreenInfo ~ delete _;
View mView;
int mCursorBlinkTicks;
SpawnedProcess mCmdSpawn ~ delete _;
SpawnedProcess mExecSpawn ~ delete _;
bool mHasConsole;
bool mMousePassThrough;
(POINT start, POINT end)? mSelection;
public this()
{
/*mScrollbar = new DarkScrollbar();
mScrollbar.mOrientation = .Vert;
mScrollbar.Init();
AddWidget(mScrollbar);*/
mScrollableWidget = new ScrollableWidget();
mScrollableWidget.InitScrollbars(false, true);
AddWidget(mScrollableWidget);
mView = new View(this);
mView.mAutoFocus = true;
mScrollableWidget.mScrollContentContainer.AddWidget(mView);
mScrollableWidget.mScrollContent = mView;
mScrollableWidget.mVertScrollbar.mOnScrollEvent.Add(new (evt) =>
{
mPaused = true;
});
}
public ~this()
{
mCmdSpawn?.Kill();
mExecSpawn?.Kill();
}
public override void Serialize(StructuredData data)
{
base.Serialize(data);
data.Add("Type", "ConsolePanel");
}
public override void AddedToParent()
{
base.AddedToParent();
}
public void Attach()
{
if (mHasConsole)
return;
mHasConsole = true;
#if BF_PLATFORM_WINDOWS
//AllocConsole();
/*ProcessStartInfo procInfo = scope ProcessStartInfo();
procInfo.UseShellExecute = false;
procInfo.SetFileName(scope $"{gApp.mInstallDir}/BeefCon_d.exe");
procInfo.SetArguments(scope $"{Process.CurrentId}");
String resultStr = scope String();
mCmdSpawn = new SpawnedProcess();
mCmdSpawn.Start(procInfo);
Thread.Sleep(2000);
var processId = mCmdSpawn.ProcessId;
if (processId > 0)
AttachConsole(processId);
else*/
AllocConsole();
var window = GetConsoleWindow();
Windows.SetWindowPos(window, default, 0, 0, 0, 0, 0x290 /* SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_HIDEWINDOW */);
ResizeComponents();
#endif
}
public void Detach()
{
if (!mHasConsole)
return;
mHasConsole = false;
#if BF_PLATFORM_WINDOWS
FreeConsole();
#endif
mCmdSpawn?.Kill();
DeleteAndNullify!(mCmdSpawn);
mExecSpawn?.Kill();
DeleteAndNullify!(mExecSpawn);
}
public override void Update()
{
base.Update();
if (mScrollableWidget.mVertScrollbar.mThumb.mMouseDown)
mPaused = true;
if (!mPaused)
{
ScreenInfo newScreenInfo = new .();
if (GetScreenInfo(newScreenInfo))
{
delete mScreenInfo;
mScreenInfo = newScreenInfo;
}
else
{
Detach();
delete newScreenInfo;
}
}
if (mScreenInfo != null)
{
if ((mPaused) || (!mHasConsole))
{
mScreenInfo.mScrollTop = (.)(mScrollableWidget.mVertScrollbar.mContentPos / mCellHeight);
int windowHeight = mScreenInfo.mInfo.mWindowRect.Height;
mScreenInfo.mInfo.mWindowRect.top = (.)mScreenInfo.mScrollTop;
mScreenInfo.mInfo.mWindowRect.bottom = (.)(mScreenInfo.mScrollTop + windowHeight);
UpdateScreenInfo(mScreenInfo);
}
}
//mPaused = false;
/*if (mUpdatingScrollPos)
{
int32 windowHeight = screenInfo.WindowHeight;
var outHandle = Console.[Friend]GetStdHandle(Console.STD_OUTPUT_HANDLE);
screenInfo.mInfo.mWindowRect.top = (.)(mScrollableWidget.mVertScrollbar.mContentPos / mCellHeight);
screenInfo.mInfo.mWindowRect.bottom = (.)(screenInfo.mInfo.mWindowRect.top + windowHeight);
var result = SetConsoleScreenBufferInfoEx(outHandle, ref screenInfo.mInfo);
CONSOLE_SCREEN_BUFFER_INFOEX info = .();
GetConsoleScreenBufferInfoEx(outHandle, ref info);
mUpdatingScrollPos = false;
}*/
if (mWidgetWindow.IsKeyDown(.Control))
{
if (mUpdateCnt % 30 == 0)
{
//var window = GetConsoleWindow();
//Windows.SetWindowPos(window, default, 0, 0, 0, 0, 0x93);
/*screenInfo.mInfo.mColorTable[7] = 0xCCCCCC;
screenInfo.mInfo.mWindowRect.top++;
screenInfo.mInfo.mWindowRect.bottom++;
//screenInfo.mInfo.mCursorY--;
var outHandle = Console.[Friend]GetStdHandle(Console.STD_OUTPUT_HANDLE);
SetConsoleScreenBufferInfoEx(outHandle, ref screenInfo.mInfo);*/
}
}
int hashCode = (mScreenInfo?.GetHashCode()).GetValueOrDefault();
if (hashCode != mLastDrawnHashCode)
{
mLastDrawnHashCode = hashCode;
MarkDirty();
}
//float height = mScreenInfo.mInfo.mHeight * mCellHeight;
//mScrollableWidget.mScrollContent.Resize(0, 0, 0, height);
//mScrollableWidget.RehupSize();
mCursorBlinkTicks++;
if (mView.mHasFocus)
MarkDirty();
}
public bool GetScreenInfo(ScreenInfo screenInfo)
{
var outHandle = Console.[Friend]GetStdHandle(Console.STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFOEX info = default;
info.mSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
#if BF_PLATFORM_WINDOWS
if (!GetConsoleScreenBufferInfoEx(outHandle, ref info))
return false;
#endif
info.mWindowRect.right++;
info.mWindowRect.bottom++;
screenInfo.mInfo = info;
screenInfo.mScrollTop = info.mWindowRect.top;
mScrollableWidget.VertScrollTo(screenInfo.mInfo.mWindowRect.top * mCellHeight);
int width = info.mWindowRect.Width;
int height = info.mWindowRect.Height;
POINT bufferSize = .(info.mWindowRect.Width, info.mWindowRect.Height);
screenInfo.mCharInfo = new .[(int32)info.mWindowRect.Width * info.mWindowRect.Height]*;
RECT readRegion = .(screenInfo.mInfo.mWindowRect.left, (.)screenInfo.mScrollTop, screenInfo.mInfo.mWindowRect.right, (.)(screenInfo.mScrollTop + screenInfo.mInfo.mWindowRect.Height - 1));
#if BF_PLATFORM_WINDOWS
ReadConsoleOutputW(outHandle, screenInfo.mCharInfo, bufferSize, POINT(0, 0), ref readRegion);
GetConsoleCursorInfo(outHandle, out screenInfo.mCursorInfo);
GetConsoleSelectionInfo(out screenInfo.mSelectionInfo);
#endif
return true;
}
public bool GetFullScreenInfo(ScreenInfo screenInfo)
{
if (screenInfo.mFullCharInfo != null)
return true;
if (screenInfo.mCharInfo == null)
{
if (!GetScreenInfo(screenInfo))
return false;
}
var outHandle = Console.[Friend]GetStdHandle(Console.STD_OUTPUT_HANDLE);
POINT bufferSize = .(screenInfo.mInfo.mWidth, screenInfo.mInfo.mHeight);
screenInfo.mFullCharInfo = new .[(int32)screenInfo.mInfo.mWidth * screenInfo.mInfo.mHeight]*;
RECT readRegion = .(0, 0, screenInfo.mInfo.mWidth, screenInfo.mInfo.mHeight);
#if BF_PLATFORM_WINDOWS
ReadConsoleOutputW(outHandle, screenInfo.mFullCharInfo, bufferSize, POINT(0, 0), ref readRegion);
#endif
return true;
}
public bool UpdateScreenInfo(ScreenInfo screenInfo)
{
if (screenInfo.mFullCharInfo == null)
{
if (!GetFullScreenInfo(screenInfo))
return false;
}
Internal.MemCpy(screenInfo.mCharInfo,
screenInfo.mFullCharInfo + screenInfo.mScrollTop * screenInfo.mInfo.mWidth,
screenInfo.mInfo.mWindowRect.Width * screenInfo.mInfo.mWindowRect.Height * sizeof(CHAR_INFO));
return true;
}
public Vector2 GetCoord(int col, int row)
{
return .(col * mCellWidth + GS!(6), row * mCellHeight + GS!(4));
}
public Vector2 GetCell(float x, float y)
{
return .((x - GS!(6)) / mCellWidth, (y - GS!(4)) / mCellHeight);
}
public override void Draw(Graphics g)
{
base.Draw(g);
var outHandle = Console.[Friend]GetStdHandle(Console.STD_OUTPUT_HANDLE);
String str = scope .(" ");
uint32[16] colorTable = .(0xFF000000, );
if (mScreenInfo != null)
{
for (int i < 16)
{
colorTable[i] = 0xFF000000 |
((mScreenInfo.mInfo.mColorTable[i] >> 16) & 0x0000FF) |
((mScreenInfo.mInfo.mColorTable[i] ) & 0x00FF00) |
((mScreenInfo.mInfo.mColorTable[i] << 16) & 0xFF0000);
}
}
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.EditBox), 0, 0, mWidth, mScrollableWidget.mHeight);
using (g.PushColor(colorTable[0]))
g.FillRect(GS!(2), GS!(2), mScrollableWidget.mVertScrollbar.mX - GS!(0), mScrollableWidget.mHeight - GS!(4));
if (mView.mHasFocus)
{
using (g.PushColor(DarkTheme.COLOR_SELECTED_OUTLINE))
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Outline), 0, 0, mWidth, mHeight);
}
if (mScreenInfo != null)
{
g.SetFont(gApp.mTermFont);
using (g.PushClip(0, 0, mScrollableWidget.mVertScrollbar.mX, mScrollableWidget.mHeight - GS!(2)))
{
int32 numVisibleCols = mScreenInfo.WindowWidth;
int32 numVisibleRows = mScreenInfo.WindowHeight;
for (int32 row < numVisibleRows)
{
for (int32 col < numVisibleCols)
{
int srcRow = row + mScreenInfo.mScrollTop;
var coord = GetCoord(col, row);
var cInfo = mScreenInfo.mCharInfo[row * mScreenInfo.WindowWidth + col];
int32 attrs = cInfo.mAttributes;
if (mScreenInfo.mSelectionInfo.mFlags != 0)
{
//TODO: Fix rendering, listen to flags.
bool selected = false;
if (srcRow == mScreenInfo.mSelectionInfo.mSelection.top)
{
selected = (col >= mScreenInfo.mSelectionInfo.mSelection.left);
if (srcRow == mScreenInfo.mSelectionInfo.mSelection.bottom)
selected &= (col <= mScreenInfo.mSelectionInfo.mSelection.right);
}
else if ((srcRow > mScreenInfo.mSelectionInfo.mSelection.top) && (srcRow < mScreenInfo.mSelectionInfo.mSelection.bottom))
{
selected = true;
}
else if (srcRow == mScreenInfo.mSelectionInfo.mSelection.bottom)
{
selected = (col <= mScreenInfo.mSelectionInfo.mSelection.right);
}
if (selected)
attrs ^= 0xFF;
}
uint32 fgColor = colorTable[(attrs & 0xF)];
uint32 bgColor = colorTable[(attrs >> 4)];
using (g.PushColor(bgColor))
{
int32 fillX = (.)coord.mX;
int32 fillY = (.)coord.mY;
int32 fillWidth = mCellWidth;
int32 fillHeight = mCellHeight;
/*if (col == 0)
{
fillX -= GS!(4);
fillWidth += GS!(4);
}
if (row == 0)
{
fillY -= GS!(2);
fillHeight += GS!(2);
}
if (row == numVisibleRows - 1)
{
}
g.FillRect(
fillX, fillY,
(col == numVisibleCols - 1) ? (mScrollableWidget.mVertScrollbar.mX - coord.mX + 1) : fillWidth,
(row == numVisibleRows - 1) ? (mView.mHeight - coord.mY) : fillHeight
);*/
g.FillRect(fillX, fillY, fillWidth, fillHeight);
}
if (cInfo.mChar > .(32))
{
str[0] = (.)cInfo.mChar;
using (g.PushColor(fgColor))
gApp.mTermFont.Draw(g, str, coord.mX, coord.mY);
}
}
}
if ((mView.mHasFocus) && (mHasConsole) && (!mPaused))
{
float brightness = (float)Math.Cos(Math.Max(0.0f, mCursorBlinkTicks - 20) / 9.0f);
brightness = Math.Clamp(brightness * 2.0f + 1.6f, 0, 1);
if (mScrollableWidget.mVertPos.IsMoving)
brightness = 0; // When we animate a pgup or pgdn, it's weird seeing the cursor scrolling around
if (brightness > 0)
{
using (g.PushColor(Color.Get(brightness)))
{
var cursorCoord = GetCoord(mScreenInfo.mInfo.mCursorX, mScreenInfo.mInfo.mCursorY - mScreenInfo.mScrollTop);
if (mScreenInfo.mCursorInfo.mVisible != 0)
{
int32 cursorHeight = (int32)mScreenInfo.mCursorInfo.mSize * mCellHeight / 100;
g.FillRect(cursorCoord.mX, cursorCoord.mY + mCellHeight - cursorHeight, mCellWidth, cursorHeight);
}
}
}
}
}
g.SetFont(DarkTheme.sDarkTheme.mSmallFont);
g.DrawString(scope $"Ln {mScreenInfo.mInfo.mCursorY + 1}", mWidth - GS!(120), mHeight - GS!(21));
g.DrawString(scope $"Col {mScreenInfo.mInfo.mCursorX + 1}", mWidth - GS!(60), mHeight - GS!(21));
}
}
public override void DrawAll(Graphics g)
{
if (!mHasConsole)
{
using (g.PushColor(0x80FFFFFF))
{
base.DrawAll(g);
}
}
else if (mPaused)
{
using (g.PushColor(0xA0FFFFFF))
{
base.DrawAll(g);
}
}
else
{
base.DrawAll(g);
}
}
public void ResizeComponents()
{
var outHandle = Console.[Friend]GetStdHandle(Console.STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFOEX info = default;
info.mSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
#if BF_PLATFORM_WINDOWS
GetConsoleScreenBufferInfoEx(outHandle, ref info);
#endif
mCellWidth = (.)gApp.mTermFont.GetWidth('W');
mCellHeight = (.)gApp.mTermFont.GetLineSpacing();
mScrollableWidget.Resize(0, 0, mWidth, Math.Max(mHeight - GS!(22), 0));
int32 cols = (.)((mWidth - GS!(2)) / mCellWidth);
int32 rows = (.)((mScrollableWidget.mHeight - GS!(8)) / mCellHeight);
mView.Resize(0, 0, mWidth, Math.Max(info.mHeight * mCellHeight, mHeight));
mScrollableWidget.RehupSize();
info.mWindowRect.right = (.)(info.mWindowRect.left + cols);
info.mWindowRect.bottom = (.)(info.mWindowRect.top + rows);
//SetConsoleScreenBufferInfoEx(outHandle, ref info);
//SetConsoleScreenBufferSize(outHandle, .((.)cols, (.)rows));
//SetConsoleWindowInfo(outHandle, true, info.mWindowRect);
#if BF_PLATFORM_WINDOWS
GetCurrentConsoleFont(outHandle, false, var fontInfo);
var window = GetConsoleWindow();
uint32 style = (.)Windows.GetWindowLong(window, Windows.GWL_STYLE);
uint32 styleEx = (.)Windows.GetWindowLong(window, Windows.GWL_EXSTYLE);
Windows.Rect rect = .(0, 0, (.)(cols * fontInfo.mSize.x), (.)(rows * fontInfo.mSize.y));
Windows.AdjustWindowRectEx(ref rect, style, false, styleEx);
Windows.SetWindowPos(window, default, 0, 0, rect.Width, rect.Height,
0x10 /* SWP_NOACTIVATE */
//0x90 /* SWP_HIDEWINDOW | SWP_NOACTIVATE */
);
#endif
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
{
base.MouseDown(x, y, btn, btnCount);
SetFocus();
}
static uint8[256*5] sKeyCharMap = .(0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0, 0, 0, 0, 0, 0,
0, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 0, 0, 0, 0, 0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 42, 43, 0, 45, 46, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 61, 44, 45, 46, 47,
96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 92, 93, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 33, 64, 35, 36, 37, 94, 38, 42, 40, 0, 0, 0, 0, 0, 0,
0, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 43, 0, 45, 46, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 43, 60, 95, 62, 63,
126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 124, 125, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0, 0, 0, 0, 0, 0,
0, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 0, 0, 0, 0, 0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 42, 43, 0, 45, 46, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 61, 44, 45, 46, 47,
96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 92, 93, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 33, 64, 35, 36, 37, 94, 38, 42, 40, 0, 0, 0, 0, 0, 0,
0, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 43, 0, 45, 46, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 43, 60, 95, 62, 63,
126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 124, 125, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
public void SysKeyDown(KeyDownEvent keyEvent)
{
if (mPaused)
{
mPaused = false;
return;
}
if (mView.mHasFocus)
{
mCursorBlinkTicks = 0;
var inHandle = Console.[Friend]GetStdHandle(Console.STD_INPUT_HANDLE);
if (keyEvent.mKeyCode != .Shift)
{
}
INPUT_RECORD input = default;
if (keyEvent.mKeyCode == .F1)
{
Debug.WriteLine("Key Events:");
while (true)
{
ReadConsoleInputW(inHandle, &input, 1, var numEventsRead);
if (input.mEventType == 1)
{
if (input.mEventData.mKeyEvent.mChar != 0)
{
int keyMod = default;
if ((input.mEventData.mKeyEvent.mControlKeyState & 8) != 0) // Ctrl
{
keyMod |= 4;
}
else
{
if ((input.mEventData.mKeyEvent.mControlKeyState & 0x10) != 0) // Shift
keyMod |= 1;
if ((input.mEventData.mKeyEvent.mControlKeyState & 0x80) != 0) // Caps Lock
keyMod |= 2;
}
/*if ((input.mEventData.mKeyEvent.mControlKeyState & 2) != 0) // Alt
flags |= .Alt;*/
Debug.WriteLine($"{input.mEventData.mKeyEvent.mVirtualKeyCode} {keyMod} : {(int)input.mEventData.mKeyEvent.mChar} {input.mEventData.mKeyEvent.mChar}");
uint16 keyState = ((uint16)keyMod << 8) + (uint16)input.mEventData.mKeyEvent.mVirtualKeyCode;
sKeyCharMap[keyState] = (uint8)input.mEventData.mKeyEvent.mChar;
}
if (input.mEventData.mKeyEvent.mChar == '?')
{
for (int i < sKeyCharMap.Count)
{
if (i % 64 == 0)
Debug.WriteLine();
Debug.Write($"{sKeyCharMap[i]}, ");
}
Debug.WriteLine();
}
}
else if (input.mEventType == 2)
{
}
}
return;
}
input.mEventType = 1 /*KEY_EVENT */;
input.mEventData.mKeyEvent.mKeyDown = 1;
input.mEventData.mKeyEvent.mRepeatCount = 1;
input.mEventData.mKeyEvent.mVirtualKeyCode = (.)keyEvent.mKeyCode;
//input.mEventData.mKeyEvent.mVirtualScanCode = 61;
int keyMod = 0;
if (keyEvent.mKeyFlags.HasFlag(.Ctrl))
{
keyMod |= 4;
}
else
{
if (keyEvent.mKeyFlags.HasFlag(.Shift))
keyMod |= 1;
if (keyEvent.mKeyFlags.HasFlag(.CapsLock))
keyMod |= 2;
}
input.mEventData.mKeyEvent.mControlKeyState = GetControlKeyState(keyEvent.mKeyFlags);
input.mEventData.mKeyEvent.mChar = (.)sKeyCharMap[(keyMod << 8) | (int)keyEvent.mKeyCode];
var result = WriteConsoleInputW(inHandle, &input, 1, var numEventsWritten);
int32 err = Windows.GetLastError();
}
}
public uint32 GetControlKeyState(KeyFlags keyFlags)
{
uint16 controlKeyState = 0;
if (keyFlags.HasFlag(.Alt))
controlKeyState |= 1;
if (keyFlags.HasFlag(.Ctrl))
controlKeyState |= 4;
if (keyFlags.HasFlag(.Shift))
controlKeyState |= 0x10;
if (keyFlags.HasFlag(.CapsLock))
controlKeyState |= 0x80;
return controlKeyState;
}
public void SysKeyUp(KeyCode keyCode)
{
if (mView.mHasFocus)
{
var inHandle = Console.[Friend]GetStdHandle(Console.STD_INPUT_HANDLE);
INPUT_RECORD input = default;
input.mEventType = 1 /*KEY_EVENT */;
input.mEventData.mKeyEvent.mVirtualKeyCode = (.)keyCode;
WriteConsoleInputW(inHandle, &input, 1, var numEventsWritten);
}
}
public override void MouseWheel(MouseEvent evt)
{
}
public override void MouseWheel(float x, float y, float deltaX, float deltaY)
{
//base.MouseWheel(x, y, deltaX, deltaY);
}
}