diff --git a/BeefLibs/corlib/src/Console.bf b/BeefLibs/corlib/src/Console.bf index 6e895987..7560c250 100644 --- a/BeefLibs/corlib/src/Console.bf +++ b/BeefLibs/corlib/src/Console.bf @@ -260,6 +260,8 @@ namespace System return OpenStreamReader(.In, ref mIn); } } + + public static bool KeyAvailable => In.CanReadNow; public static Result Read() => In.Read(); diff --git a/BeefLibs/corlib/src/IO/FileStream.bf b/BeefLibs/corlib/src/IO/FileStream.bf index 9979b729..933b4ac9 100644 --- a/BeefLibs/corlib/src/IO/FileStream.bf +++ b/BeefLibs/corlib/src/IO/FileStream.bf @@ -62,7 +62,7 @@ namespace System.IO return numBytesRead; } - public virtual Result TryRead(Span data, int timeoutMS) + public override Result TryRead(Span data, int timeoutMS) { Platform.BfpFileResult result = .Ok; int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result); @@ -513,7 +513,7 @@ namespace System.IO return numBytesRead; } - public Result TryRead(Span data, int timeoutMS) + public override Result TryRead(Span data, int timeoutMS) { if (mBfpFilePos != mPos) Try!(SeekUnderlying(mPos)); diff --git a/BeefLibs/corlib/src/IO/Stream.bf b/BeefLibs/corlib/src/IO/Stream.bf index a7bbd32a..fc863dc2 100644 --- a/BeefLibs/corlib/src/IO/Stream.bf +++ b/BeefLibs/corlib/src/IO/Stream.bf @@ -60,6 +60,20 @@ namespace System.IO } public abstract Result TryRead(Span data); + public virtual Result TryRead(Span data, int timeout) + { + if (timeout == -1) + { + switch (TryRead(data)) + { + case .Ok(var i): + return i; + case .Err: + return .Err(.ReadError(.Unknown)); + } + } + return .Err(.ReadError(.Unknown)); + } public abstract Result TryWrite(Span data); public abstract Result Close(); diff --git a/BeefLibs/corlib/src/IO/StreamReader.bf b/BeefLibs/corlib/src/IO/StreamReader.bf index 4e4d6568..a06e38f7 100644 --- a/BeefLibs/corlib/src/IO/StreamReader.bf +++ b/BeefLibs/corlib/src/IO/StreamReader.bf @@ -50,6 +50,7 @@ namespace System.IO private int32 mMaxCharsPerBuffer; private Encoding mEncoding; + private bool mPendingNewlineCheck; public Stream BaseStream { @@ -167,6 +168,18 @@ namespace System.IO } } + public bool CanReadNow + { + get + { + if (mCharPos < mCharLen) + return true; + if (ReadBuffer(true) case .Ok(let count)) + return count > 0; + return false; + } + } + public Result Open(StringView fileName) { Contract.Assert(mStream == null); @@ -393,7 +406,7 @@ namespace System.IO } } - protected virtual Result ReadBuffer() + protected virtual Result ReadBuffer(bool zeroWait = false) { mCharLen = 0; mCharPos = 0; @@ -405,7 +418,7 @@ namespace System.IO if (mCheckPreamble) { //Contract.Assert(bytePos <= _preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); - int len = Try!(mStream.TryRead(.(mByteBuffer, mBytePos, mByteBuffer.Count - mBytePos))); + int len = Try!(mStream.TryRead(.(mByteBuffer, mBytePos, mByteBuffer.Count - mBytePos), zeroWait ? 0 : -1)); /*switch (mStream.Read(mByteBuffer, mBytePos, mByteBuffer.Length - mBytePos)) { case .Ok(var gotLen): @@ -437,7 +450,7 @@ namespace System.IO { //Contract.Assert(bytePos == 0, "bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?"); - mByteLen = Try!(mStream.TryRead(.(mByteBuffer, 0, mByteBuffer.Count))); + mByteLen = Try!(mStream.TryRead(.(mByteBuffer, 0, mByteBuffer.Count), zeroWait ? 0 : -1)); /*switch (mStream.Read(mByteBuffer, 0, mByteBuffer.Length)) { case .Ok(var byteLen): @@ -488,9 +501,13 @@ namespace System.IO } } - + if ((mPendingNewlineCheck) && (mCharPos < mCharLen)) + { + if (mCharBuffer[mCharPos] == '\n') mCharPos++; + mPendingNewlineCheck = false; + } } - while (mCharLen == 0); + while (mCharLen == mCharPos); //Console.WriteLine("ReadBuffer called. chars: "+char8Len); return mCharLen; @@ -551,10 +568,18 @@ namespace System.IO strBuffer.Append(mCharBuffer.CArray() + mCharPos, i - mCharPos); mCharPos = i + 1; - if (ch == '\r' && (mCharPos < mCharLen || Try!(ReadBuffer()) > 0)) + if (ch == '\r') { - if (mCharBuffer[mCharPos] == '\n') mCharPos++; + if (mCharPos < mCharLen) + { + if (mCharBuffer[mCharPos] == '\n') mCharPos++; + } + else + { + mPendingNewlineCheck = true; + } } + return .Ok; } i++; diff --git a/BeefySysLib/platform/win/Platform.cpp b/BeefySysLib/platform/win/Platform.cpp index 0f2cf93f..0fc86b97 100644 --- a/BeefySysLib/platform/win/Platform.cpp +++ b/BeefySysLib/platform/win/Platform.cpp @@ -3043,7 +3043,48 @@ static void WINAPI OverlappedReadComplete(DWORD dwErrorCode, DWORD dwNumberOfByt BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Read(BfpFile* file, void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult) { - if (timeoutMS != -1) + bool forceNormalRead = false; + + if ((file->mIsStd) && (file->mHandle == GetStdHandle(STD_INPUT_HANDLE))) + { + INPUT_RECORD record; + DWORD numRead; + while (true) + { + if (timeoutMS != -1) + { + if (!GetNumberOfConsoleInputEvents(file->mHandle, &numRead)) + { + forceNormalRead = true; + break; + } + + if (numRead == 0) + { + OUTRESULT(BfpFileResult_Timeout); + return 0; + } + } + + if (!ReadConsoleInput(file->mHandle, &record, 1, &numRead)) + { + forceNormalRead = true; + break; + } + if (numRead > 0) + { + if ((record.Event.KeyEvent.bKeyDown) && (record.Event.KeyEvent.uChar.AsciiChar != 0)) + { + memset(buffer, record.Event.KeyEvent.uChar.AsciiChar, 1); + OUTRESULT(BfpFileResult_Ok); + return 1; + } + } + } + + } + + if ((timeoutMS != -1) && (!forceNormalRead)) { if (file->mAsyncData == NULL) {