// Native console client. RSSRV owns the logical console; this file speaks its Port protocol. #include #include #include #include #include #include static volatile long gDefaultConsoleSession; static KSTATUS NtlConsoleGetDefaultSession(SYS_HANDLE* sessionOut); // Connects to RSSRV's native console service. KSTATUS NtlConsoleConnect(SYS_HANDLE* sessionOut) { if (!sessionOut) return NTLSTATUS_INVALID_PARAMETER; *sessionOut = SYS_HANDLE_INVALID; SYS_HANDLE resourceSession = SYS_HANDLE_INVALID; KSTATUS status = NtlResourceConnect(&resourceSession); if (!KSUCCESS(status)) return status; SYS_HANDLE listener = SYS_HANDLE_INVALID; status = NtlResourceLookup(resourceSession, SYS_SV_LITERAL(NTL_CONSOLE_SERVICE_PATH), SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT, &listener); (void)NtlResourceClose(resourceSession); if (!KSUCCESS(status)) return status; status = NtlResourceConnectListener(listener, sessionOut); (void)SysCloseHandle(listener); return status; } // Disconnects one console service session. KSTATUS NtlConsoleClose(SYS_HANDLE session) { if (session == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_PARAMETER; (void)SysDisconnectPort(session); return SysCloseHandle(session); } // Returns one process-local cached console session. static KSTATUS NtlConsoleGetDefaultSession(SYS_HANDLE* sessionOut) { if (!sessionOut) return NTLSTATUS_INVALID_PARAMETER; long current = gDefaultConsoleSession; if (current != 0) { *sessionOut = (SYS_HANDLE)(uint32_t)current; return NTLSTATUS_SUCCESS; } SYS_HANDLE created = SYS_HANDLE_INVALID; KSTATUS status = NtlConsoleConnect(&created); if (!KSUCCESS(status)) return status; long previous = _InterlockedCompareExchange(&gDefaultConsoleSession, (long)created, 0); if (previous != 0) { (void)NtlConsoleClose(created); created = (SYS_HANDLE)(uint32_t)previous; } *sessionOut = created; return NTLSTATUS_SUCCESS; } // Executes one fixed console request and validates the reply envelope. static KSTATUS NtlConsoleCall(SYS_HANDLE session, const NTL_CONSOLE_REQUEST* request, NTL_CONSOLE_REPLY* replyOut) { if (!request || !replyOut) return NTLSTATUS_INVALID_PARAMETER; if (session == SYS_HANDLE_INVALID) { KSTATUS status = NtlConsoleGetDefaultSession(&session); if (!KSUCCESS(status)) return status; } NTL_CONSOLE_REPLY reply; memset(&reply, 0, sizeof(reply)); SYS_PORT_MESSAGE_INFO info; memset(&info, 0, sizeof(info)); info.Size = sizeof(info); SYS_CALL_PORT_REQUEST call; memset(&call, 0, sizeof(call)); call.Size = sizeof(call); call.EndpointHandle = session; call.Flags = SYS_PORT_FLAG_NONE; call.RequestPayload = request; call.RequestLength = sizeof(*request); call.ReplyPayload = &reply; call.ReplyCapacity = sizeof(reply); call.ReplyInfoOut = &info; call.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; KSTATUS status = SysCallPort(&call); if (!KSUCCESS(status)) return status; if (info.Type != SYS_PORT_MESSAGE_REPLY || info.PayloadLength != sizeof(reply) || info.HandleCount != 0 || reply.Size != sizeof(reply) || reply.Version != NTL_CONSOLE_PROTOCOL_VERSION || reply.Operation != request->Operation || reply.Flags != NTL_CONSOLE_FLAG_NONE) return NTLSTATUS_FAILURE; *replyOut = reply; return reply.Status; } // Writes arbitrary bytes to the console in bounded protocol chunks. KSTATUS NtlConsoleWrite(SYS_HANDLE session, const void* data, size_t length, size_t* writtenOut) { if (writtenOut) *writtenOut = 0; if (length && !data) return NTLSTATUS_INVALID_PARAMETER; const char* bytes = (const char*)data; size_t total = 0; while (total < length) { size_t chunk = length - total; if (chunk > NTL_CONSOLE_WRITE_MAX) chunk = NTL_CONSOLE_WRITE_MAX; NTL_CONSOLE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_CONSOLE_PROTOCOL_VERSION; request.Operation = NTL_CONSOLE_OP_WRITE; request.Flags = NTL_CONSOLE_FLAG_NONE; request.Data.Write.Length = (uint32_t)chunk; memcpy(request.Data.Write.Data, bytes + total, chunk); NTL_CONSOLE_REPLY reply; memset(&reply, 0, sizeof(reply)); KSTATUS status = NtlConsoleCall(session, &request, &reply); total += reply.Written; if (!KSUCCESS(status) || reply.Written != chunk) { if (writtenOut) *writtenOut = total; return KSUCCESS(status) ? NTLSTATUS_FAILURE : status; } } if (writtenOut) *writtenOut = total; return NTLSTATUS_SUCCESS; } // Queries the logical console's current dimensions and cursor state. KSTATUS NtlConsoleQueryInfo(SYS_HANDLE session, NTL_CONSOLE_INFO* infoOut) { if (!infoOut) return NTLSTATUS_INVALID_PARAMETER; NTL_CONSOLE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_CONSOLE_PROTOCOL_VERSION; request.Operation = NTL_CONSOLE_OP_QUERY_INFO; NTL_CONSOLE_REPLY reply; KSTATUS status = NtlConsoleCall(session, &request, &reply); if (KSUCCESS(status)) *infoOut = reply.Info; return status; } // Executes one console operation whose reply has only status and optional written count. static KSTATUS NtlConsoleSimpleCall(SYS_HANDLE session, NTL_CONSOLE_REQUEST* request, uint32_t* writtenOut) { NTL_CONSOLE_REPLY reply; memset(&reply, 0, sizeof(reply)); KSTATUS status = NtlConsoleCall(session, request, &reply); if (writtenOut) *writtenOut = reply.Written; return status; } // Updates the logical console cursor. KSTATUS NtlConsoleSetCursor(SYS_HANDLE session, int x, int y) { NTL_CONSOLE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_CONSOLE_PROTOCOL_VERSION; request.Operation = NTL_CONSOLE_OP_SET_CURSOR; request.Data.Cursor.X = x; request.Data.Cursor.Y = y; return NtlConsoleSimpleCall(session, &request, 0); } // Fills console characters over one linear cell range. KSTATUS NtlConsoleFillCharacter(SYS_HANDLE session, char character, int x, int y, size_t length, size_t* writtenOut) { if (writtenOut) *writtenOut = 0; if (length > UINT32_MAX) return NTLSTATUS_INVALID_PARAMETER; NTL_CONSOLE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_CONSOLE_PROTOCOL_VERSION; request.Operation = NTL_CONSOLE_OP_FILL_CHARACTER; request.Data.FillCharacter.Character = character; request.Data.FillCharacter.X = x; request.Data.FillCharacter.Y = y; request.Data.FillCharacter.Length = (uint32_t)length; uint32_t written = 0; KSTATUS status = NtlConsoleSimpleCall(session, &request, &written); if (writtenOut) *writtenOut = written; return status; } // Fills console attributes over one linear cell range. KSTATUS NtlConsoleFillAttribute(SYS_HANDLE session, uint16_t attribute, int x, int y, size_t length, size_t* writtenOut) { if (writtenOut) *writtenOut = 0; if (length > UINT32_MAX) return NTLSTATUS_INVALID_PARAMETER; NTL_CONSOLE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_CONSOLE_PROTOCOL_VERSION; request.Operation = NTL_CONSOLE_OP_FILL_ATTRIBUTE; request.Data.FillAttribute.Attribute = attribute; request.Data.FillAttribute.X = x; request.Data.FillAttribute.Y = y; request.Data.FillAttribute.Length = (uint32_t)length; uint32_t written = 0; KSTATUS status = NtlConsoleSimpleCall(session, &request, &written); if (writtenOut) *writtenOut = written; return status; } // Draws one glyph at explicit pixel coordinates without moving console state. KSTATUS NtlConsolePutCharacter(SYS_HANDLE session, char character, int x, int y, uint32_t foreground, uint32_t background) { NTL_CONSOLE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_CONSOLE_PROTOCOL_VERSION; request.Operation = NTL_CONSOLE_OP_PUT_CHARACTER; request.Data.PutCharacter.Character = character; request.Data.PutCharacter.X = x; request.Data.PutCharacter.Y = y; request.Data.PutCharacter.Foreground = foreground; request.Data.PutCharacter.Background = background; return NtlConsoleSimpleCall(session, &request, 0); } // Clears the console's current display target. KSTATUS NtlConsoleClear(SYS_HANDLE session, uint32_t color) { NTL_CONSOLE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_CONSOLE_PROTOCOL_VERSION; request.Operation = NTL_CONSOLE_OP_CLEAR; request.Data.Clear.Color = color; return NtlConsoleSimpleCall(session, &request, 0); } // Executes one console input operation and returns its key record. static KSTATUS NtlConsoleInputCall(SYS_HANDLE session, uint32_t operation, uint64_t timeoutMilliseconds, INPUT_KEY_RECORD* recordOut) { NTL_CONSOLE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_CONSOLE_PROTOCOL_VERSION; request.Operation = operation; request.TimeoutMilliseconds = timeoutMilliseconds; NTL_CONSOLE_REPLY reply; KSTATUS status = NtlConsoleCall(session, &request, &reply); if (KSUCCESS(status) && recordOut) *recordOut = reply.Input; return status; } // Reads one logical console input record. KSTATUS NtlConsoleReadInput(SYS_HANDLE session, uint64_t timeoutMilliseconds, INPUT_KEY_RECORD* recordOut) { if (!recordOut) return NTLSTATUS_INVALID_PARAMETER; return NtlConsoleInputCall(session, NTL_CONSOLE_OP_READ_INPUT, timeoutMilliseconds, recordOut); } // Peeks one logical console input record. KSTATUS NtlConsolePeekInput(SYS_HANDLE session, uint64_t timeoutMilliseconds, INPUT_KEY_RECORD* recordOut) { if (!recordOut) return NTLSTATUS_INVALID_PARAMETER; return NtlConsoleInputCall(session, NTL_CONSOLE_OP_PEEK_INPUT, timeoutMilliseconds, recordOut); } // Discards every queued logical console input record. KSTATUS NtlConsoleFlushInput(SYS_HANDLE session) { NTL_CONSOLE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_CONSOLE_PROTOCOL_VERSION; request.Operation = NTL_CONSOLE_OP_FLUSH_INPUT; return NtlConsoleSimpleCall(session, &request, 0); } // Reads until one console key record has a character representation. KSTATUS NtlConsoleReadCharacter(SYS_HANDLE session, char* characterOut) { if (!characterOut) return NTLSTATUS_INVALID_PARAMETER; for (;;) { INPUT_KEY_RECORD record; KSTATUS status = NtlConsoleReadInput(session, SYS_PORT_TIMEOUT_INFINITE, &record); if (!KSUCCESS(status)) return status; if (record.Char != 0) { *characterOut = record.Char; return NTLSTATUS_SUCCESS; } } }