[*] Early internal non-canonical TTY api

This commit is contained in:
Reece Wilson 2022-05-18 19:14:24 +01:00
parent 6fb3f3a9e5
commit a02bb0aabd
3 changed files with 303 additions and 15 deletions

View File

@ -15,6 +15,8 @@
#include <Source/Loop/LSHandle.hpp>
#include <Source/Loop/LSEvent.hpp>
#include <Source/Console/ConsoleTTY/ConsoleTTY.hpp>
#if defined(AURORA_IS_MODERNNT_DERIVED) || defined(AURORA_IS_POSIX_DERIVED)
#if defined(AURORA_IS_MODERNNT_DERIVED)
@ -77,6 +79,7 @@ namespace Aurora::Console::ConsoleStd
using StreamHandle_t = HANDLE;
static StreamHandle_t gWin32Thread = INVALID_HANDLE_VALUE;
static DWORD gCanonicalBackup {};
#elif defined(IO_POSIX_STREAMS)
#define DEFAULT_HANDLE_VAL 0xFFFFFFFF
using StreamHandle_t = int;
@ -95,16 +98,21 @@ namespace Aurora::Console::ConsoleStd
static StreamHandle_t gInputStream = DEFAULT_HANDLE_VAL;
static StreamHandle_t gOutputStream = DEFAULT_HANDLE_VAL;
static AuSPtr<ConsoleHasDataLoopSource> gLoopSource;
static bool gCanonicalEnabled {};
static AuList<CanonicalInput> gCanonicalBuffer;
//static AuThreadPrimitives::MutexUnique_t gRingLock = AuThreadPrimitives::MutexUnique();
static AuThreadPrimitives::SpinLock gRingLock;// = AuThreadPrimitives::MutexUnique();
#if defined(AURORA_IS_MODERNNT_DERIVED)
void ProcessCanonical();
static DWORD WINAPI StdInWin32Thread(void*)
{
HANDLE a[2] = {gInputStream, gTerminateConsole};
while (true)
while (!gCanonicalEnabled)
{
WaitForMultipleObjectsEx(2, a, false, 25, 0);
@ -118,8 +126,262 @@ namespace Aurora::Console::ConsoleStd
return 1;
}
#endif
void ProcessCanonical(HANDLE h)
{
INPUT_RECORD records[4096];
DWORD dwRecords;
void *data = &gLineEncodedBuffer[gEncodedIndex];
auto length = kLineBufferMax - gEncodedIndex;
if (!IS_STREAM_HANDLE_VALID(h))
{
h = gInputStream;
}
if (length == 0)
{
return;
}
if (!GetNumberOfConsoleInputEvents(h,
&dwRecords))
{
return;
}
dwRecords = AuMin(dwRecords, DWORD(AuArraySize(records)));
if (!dwRecords)
{
return;
}
if (!ReadConsoleInputW(h,
records,
dwRecords,
&dwRecords))
{
return;
}
AU_LOCK_GUARD(gRingLock);
gCanonicalBuffer.reserve(4096);
for (int i = 0; i < dwRecords; i++)
{
int z;
bool dBreak = false;
CanonicalInput canInput;
canInput.type = ECanonicalInput::eEnumInvalid;
canInput.scrollDeltaY = 0;
auto &record = records[i];
AuString key;
switch (record.EventType)
{
case KEY_EVENT:
if (!record.Event.KeyEvent.bKeyDown)
{
dBreak = true;
break;
}
if (record.Event.KeyEvent.wVirtualKeyCode <= VK_HELP &&
record.Event.KeyEvent.wVirtualKeyCode != VK_SPACE)
{
switch (record.Event.KeyEvent.wVirtualKeyCode)
{
case VK_UP:
canInput.type = ECanonicalInput::eArrowUp;
break;
case VK_DOWN:
canInput.type = ECanonicalInput::eArrowDown;
break;
case VK_LEFT:
canInput.type = ECanonicalInput::eArrowLeft;
break;
case VK_RIGHT:
canInput.type = ECanonicalInput::eArrowRight;
break;
case VK_HOME:
canInput.type = ECanonicalInput::eHome;
break;
case VK_BACK:
canInput.type = ECanonicalInput::eBackspace;
break;
case VK_PRIOR:
canInput.type = ECanonicalInput::ePageUp;
break;
case VK_NEXT:
canInput.type = ECanonicalInput::ePageDown;
break;
case VK_RETURN:
canInput.type = ECanonicalInput::eEnter;
break;
default:
dBreak = true;
}
}
else
{
canInput.type = ECanonicalInput::eInput;
key = AuLocale::ConvertFromWChar(&record.Event.KeyEvent.uChar.UnicodeChar, 1);
if (key.empty())
{
return;
}
for (z = 0; z < record.Event.KeyEvent.wRepeatCount; z++)
{
canInput.keyUp += key;
}
}
break;
case MOUSE_EVENT:
if (record.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED)
{
canInput.type = ECanonicalInput::eScroll;
canInput.scrollDeltaY = AuStaticCast<AuInt16>(AuBitsToHigher((AuUInt32)record.Event.MouseEvent.dwButtonState));
if (canInput.scrollDeltaY > 1)
canInput.scrollDeltaY = 1;
else if (canInput.scrollDeltaY < -1)
canInput.scrollDeltaY = -1;
}
else
{
dBreak = true;
}
break;
default:
dBreak = true;
break;
};
if (dBreak) continue;
if (!AuTryInsert(gCanonicalBuffer, canInput))
{
return;
}
}
}
void ProcessCanonical()
{
ProcessCanonical(INVALID_HANDLE_VALUE);
}
void SignalKillNT()
{
if (IS_STREAM_HANDLE_VALID(gWin32Thread))
{
CancelSynchronousIo(gWin32Thread);
}
if (IS_STREAM_HANDLE_VALID(gTerminateConsole))
{
SetEvent(gTerminateConsole);
}
if (WaitForSingleObject(gWin32Thread, 200) != WAIT_OBJECT_0)
{
TerminateThread(gWin32Thread, 0);
}
AuWin32CloseHandle(gWin32Thread);
}
bool EnterCanMode()
{
DWORD mode;
if (!GetConsoleMode(gInputStream, &mode))
{
return false;
}
gCanonicalBackup = mode;
mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_QUICK_EDIT_MODE);
mode |= ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT | ENABLE_EXTENDED_FLAGS;
SetConsoleMode(gInputStream, mode);
gCanonicalEnabled = true;
SignalKillNT();
INPUT_RECORD niceWorkMicrosoft[2] {};
niceWorkMicrosoft[0].EventType = KEY_EVENT;
niceWorkMicrosoft[0].Event.KeyEvent.bKeyDown = TRUE;
niceWorkMicrosoft[0].Event.KeyEvent.dwControlKeyState = 0;
niceWorkMicrosoft[0].Event.KeyEvent.wRepeatCount = 1;
niceWorkMicrosoft[0].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
niceWorkMicrosoft[0].Event.KeyEvent.uChar.UnicodeChar = '\r';
niceWorkMicrosoft[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
niceWorkMicrosoft[1].EventType = KEY_EVENT;
niceWorkMicrosoft[1].Event.KeyEvent.bKeyDown = FALSE;
niceWorkMicrosoft[1].Event.KeyEvent.dwControlKeyState = 0;
niceWorkMicrosoft[1].Event.KeyEvent.wRepeatCount = 1;
niceWorkMicrosoft[1].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
niceWorkMicrosoft[1].Event.KeyEvent.uChar.UnicodeChar = '\r';
niceWorkMicrosoft[1].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
DWORD idc;
WriteConsoleInputW(gInputStream, niceWorkMicrosoft, 2, &idc);
return true;
}
void LeaveCanMode()
{
if (!AuExchange(gCanonicalEnabled, false))
{
return;
}
SetConsoleMode(gInputStream, gCanonicalBackup);
gWin32Thread = CreateThread(nullptr, 0, StdInWin32Thread, nullptr, 0, nullptr);
}
#else
bool EnterCanMode()
{
}
void LeaveCanMode()
{
}
void ProcessCanonical()
{
}
#endif
AuList<CanonicalInput> DebufferCanonicalInput()
{
AU_LOCK_GUARD(gRingLock);
return AuExchange(gCanonicalBuffer, {});
}
bool ConsoleHasDataLoopSource::IsSignaled()
{
@ -625,7 +887,6 @@ namespace Aurora::Console::ConsoleStd
if (gRuntimeConfig.console.enableStdPassthrough && gRuntimeConfig.console.enableStdIn)
{
if (gLoopSource)
{
gLoopSource->Set();
@ -675,16 +936,10 @@ namespace Aurora::Console::ConsoleStd
#if defined(AURORA_IS_MODERNNT_DERIVED)
if (IS_STREAM_HANDLE_VALID(gWin32Thread))
{
CancelSynchronousIo(gWin32Thread);
if (WaitForSingleObject(gWin32Thread, 200) != WAIT_OBJECT_0)
{
TerminateThread(gWin32Thread, 0);
}
}
gCanonicalEnabled = false;
SignalKillNT();
AuWin32CloseHandle(gWin32Thread);
AuWin32CloseHandle(gTerminateConsole);
// Note: CloseHandle in the middle of a ReadFile blocks

View File

@ -28,4 +28,38 @@ namespace Aurora::Console::ConsoleStd
AuUInt32 WriteStdOut(const void *data, AuUInt32 length);
void WriteStdOut(AuUInt8 level, const ConsoleMessage &msg);
AUE_DEFINE(ECanonicalInput,
(
eInput,
eArrowUp,
eArrowDown,
eArrowRight,
eArrowLeft,
eHome,
eBackspace,
ePageUp,
ePageDown,
eScroll,
eEnter
));
struct CanonicalInput
{
ECanonicalInput type;
AuString keyUp;
int scrollDeltaY;
};
bool EnterCanMode();
void LeaveCanMode();
AuList<CanonicalInput> DebufferCanonicalInput();
void ProcessCanonical();
#if defined(AURORA_IS_MODERNNT_DERIVED)
void ProcessCanonical(HANDLE h);
#endif
}

View File

@ -423,7 +423,7 @@ namespace Aurora::Console::ConsoleTTY
SetConsoleWindowInfo(gConsoles[0].h, true, &screen);
SetConsoleWindowInfo(gConsoles[1].h, true, &screen);
return false;
return true;
}
if (((res.first == curConsole.width &&
@ -523,7 +523,6 @@ namespace Aurora::Console::ConsoleTTY
if (!IdkMan())
{
gIsRecording = false;
gRecordedActions.clear();
return false;
}