[*] Early internal non-canonical TTY api
This commit is contained in:
parent
6fb3f3a9e5
commit
a02bb0aabd
@ -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
|
||||
|
@ -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
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user