From cc05ca5acb82c2bb923195d07fa5564341f80cb0 Mon Sep 17 00:00:00 2001 From: Phillip Susi Date: Tue, 11 Jul 2000 04:09:25 +0000 Subject: [PATCH] Implemented console modes svn path=/trunk/; revision=1264 --- reactos/include/csrss/csrss.h | 21 ++++ reactos/include/ntos/console.h | 15 +-- reactos/lib/kernel32/misc/console.c | 34 ++++++- reactos/subsys/csrss/api.h | 7 ++ reactos/subsys/csrss/api/conio.c | 145 +++++++++++++++++++++++++--- reactos/subsys/csrss/api/wapi.c | 4 +- 6 files changed, 199 insertions(+), 27 deletions(-) diff --git a/reactos/include/csrss/csrss.h b/reactos/include/csrss/csrss.h index 7b88e14d5ba..99d02676550 100644 --- a/reactos/include/csrss/csrss.h +++ b/reactos/include/csrss/csrss.h @@ -152,6 +152,22 @@ typedef struct CHAR Attrib; } CSRSS_SET_ATTRIB_REQUEST, *PCSRSS_SET_ATTRIB_REQUEST; +typedef struct +{ + HANDLE ConsoleHandle; + DWORD Mode; +} CSRSS_SET_CONSOLE_MODE_REQUEST, *PCSRSS_SET_CONSOLE_MODE_REQUEST; + +typedef struct +{ + HANDLE ConsoleHandle; +} CSRSS_GET_CONSOLE_MODE_REQUEST, *PCSRSS_GET_CONSOLE_MODE_REQUEST; + +typedef struct +{ + DWORD ConsoleMode; +} CSRSS_GET_CONSOLE_MODE_REPLY, *PCSRSS_GET_CONSOLE_MODE_REPLY; + #define CSRSS_MAX_WRITE_CONSOLE_REQUEST (MAX_MESSAGE_DATA - sizeof( ULONG ) - sizeof( CSRSS_WRITE_CONSOLE_REQUEST)) #define CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR (MAX_MESSAGE_DATA - sizeof( ULONG ) - sizeof( CSRSS_WRITE_CONSOLE_OUTPUT_CHAR_REQUEST )) @@ -176,6 +192,8 @@ typedef struct #define CSRSS_GET_CURSOR_INFO (0xE) #define CSRSS_SET_CURSOR_INFO (0xF) #define CSRSS_SET_ATTRIB (0x10) +#define CSRSS_GET_MODE (0x11) +#define CSRSS_SET_MODE (0x12) typedef struct { @@ -197,6 +215,8 @@ typedef struct CSRSS_SET_CURSOR_INFO_REQUEST SetCursorInfoRequest; CSRSS_GET_CURSOR_INFO_REQUEST GetCursorInfoRequest; CSRSS_SET_ATTRIB_REQUEST SetAttribRequest; + CSRSS_SET_CONSOLE_MODE_REQUEST SetConsoleModeRequest; + CSRSS_GET_CONSOLE_MODE_REQUEST GetConsoleModeRequest; } Data; } CSRSS_API_REQUEST, *PCSRSS_API_REQUEST; @@ -216,6 +236,7 @@ typedef struct CSRSS_WRITE_CONSOLE_OUTPUT_CHAR_REPLY WriteConsoleOutputCharReply; CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB_REPLY WriteConsoleOutputAttribReply; CSRSS_GET_CURSOR_INFO_REPLY GetCursorInfoReply; + CSRSS_GET_CONSOLE_MODE_REPLY GetConsoleModeReply; } Data; } CSRSS_API_REPLY, *PCSRSS_API_REPLY; diff --git a/reactos/include/ntos/console.h b/reactos/include/ntos/console.h index d1443ac561d..e04371040e4 100644 --- a/reactos/include/ntos/console.h +++ b/reactos/include/ntos/console.h @@ -14,13 +14,14 @@ #define __INCLUDE_CONSOLE_H /* GetConsoleMode */ -#define ENABLE_LINE_INPUT (2) -#define ENABLE_ECHO_INPUT (4) -#define ENABLE_PROCESSED_INPUT (1) -#define ENABLE_WINDOW_INPUT (8) -#define ENABLE_MOUSE_INPUT (16) -#define ENABLE_PROCESSED_OUTPUT (1) -#define ENABLE_WRAP_AT_EOL_OUTPUT (2) +#define ENABLE_LINE_INPUT (0x02) +#define ENABLE_ECHO_INPUT (0x04) +#define ENABLE_PROCESSED_INPUT (0x01) +#define ENABLE_WINDOW_INPUT (0x08) +#define ENABLE_MOUSE_INPUT (0x0f) +#define CONSOLE_MODE_VALID (0x1f) +#define ENABLE_PROCESSED_OUTPUT (0x01) +#define ENABLE_WRAP_AT_EOL_OUTPUT (0x02) typedef struct _CONSOLE_SCREEN_BUFFER_INFO { COORD dwSize; diff --git a/reactos/lib/kernel32/misc/console.c b/reactos/lib/kernel32/misc/console.c index d8c35ed5d91..5c07c6e0fc8 100644 --- a/reactos/lib/kernel32/misc/console.c +++ b/reactos/lib/kernel32/misc/console.c @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.24 2000/07/01 17:07:00 ea Exp $ +/* $Id: console.c,v 1.25 2000/07/11 04:06:42 phreak Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries @@ -801,8 +801,20 @@ GetConsoleMode( LPDWORD lpMode ) { - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + CSRSS_API_REQUEST Request; + CSRSS_API_REPLY Reply; + NTSTATUS Status; + + Request.Type = CSRSS_GET_MODE; + Request.Data.GetConsoleModeRequest.ConsoleHandle = hConsoleHandle; + Status = CsrClientCallServer( &Request, &Reply, sizeof( CSRSS_API_REQUEST ), sizeof( CSRSS_API_REPLY ) ); + if( !NT_SUCCESS( Status ) || !NT_SUCCESS( Status = Reply.Status ) ) + { + SetLastErrorByStatus ( Status ); + return FALSE; + } + *lpMode = Reply.Data.GetConsoleModeReply.ConsoleMode; + return TRUE; } @@ -895,8 +907,20 @@ SetConsoleMode( DWORD dwMode ) { - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + CSRSS_API_REQUEST Request; + CSRSS_API_REPLY Reply; + NTSTATUS Status; + + Request.Type = CSRSS_SET_MODE; + Request.Data.SetConsoleModeRequest.ConsoleHandle = hConsoleHandle; + Request.Data.SetConsoleModeRequest.Mode = dwMode; + Status = CsrClientCallServer( &Request, &Reply, sizeof( CSRSS_API_REQUEST ), sizeof( CSRSS_API_REPLY ) ); + if( !NT_SUCCESS( Status ) || !NT_SUCCESS( Status = Reply.Status ) ) + { + SetLastErrorByStatus ( Status ); + return FALSE; + } + return TRUE; } diff --git a/reactos/subsys/csrss/api.h b/reactos/subsys/csrss/api.h index 2d8fa9fa4db..a868b4cca09 100644 --- a/reactos/subsys/csrss/api.h +++ b/reactos/subsys/csrss/api.h @@ -32,6 +32,9 @@ typedef struct CSRSS_CONSOLE_t BYTE DefaultAttrib; /* default char attribute */ LIST_ENTRY InputEvents; /* List head for input event queue */ CONSOLE_CURSOR_INFO CursorInfo; + DWORD ConsoleMode; + WORD WaitingChars; + WORD WaitingLines; /* number of chars and lines in input queue */ } CSRSS_CONSOLE, *PCSRSS_CONSOLE; typedef struct @@ -94,6 +97,10 @@ NTSTATUS CsrSetCursorInfo( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST R NTSTATUS CsrSetTextAttrib( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST Request, PCSRSS_API_REPLY Reply ); +NTSTATUS CsrSetConsoleMode( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST Request, PCSRSS_API_REPLY Reply ); + +NTSTATUS CsrGetConsoleMode( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST Request, PCSRSS_API_REPLY Reply ); + /* print.c */ VOID DisplayString(LPCWSTR lpwString); VOID PrintString (char* fmt, ...); diff --git a/reactos/subsys/csrss/api/conio.c b/reactos/subsys/csrss/api/conio.c index 46650eb59e6..82040c549a7 100644 --- a/reactos/subsys/csrss/api/conio.c +++ b/reactos/subsys/csrss/api/conio.c @@ -1,4 +1,4 @@ -/* $Id: conio.c,v 1.9 2000/07/07 01:16:50 phreak Exp $ +/* $Id: conio.c,v 1.10 2000/07/11 04:09:25 phreak Exp $ * * reactos/subsys/csrss/api/conio.c * @@ -105,7 +105,7 @@ NTSTATUS CsrReadConsole(PCSRSS_PROCESS_DATA ProcessData, { ConsoleInput *Input; PCHAR Buffer; - int i; + int i = 0; ULONG nNumberOfCharsToRead; PCSRSS_CONSOLE Console; NTSTATUS Status; @@ -128,16 +128,34 @@ NTSTATUS CsrReadConsole(PCSRSS_PROCESS_DATA ProcessData, return Status; } RtlEnterCriticalSection( &ActiveConsoleLock ); - for (i=0; iInputEvents.Flink != &Console->InputEvents; i++ ) - { - Input = (ConsoleInput *)Console->InputEvents.Flink; - Input->ListEntry.Blink->Flink = Input->ListEntry.Flink; - Input->ListEntry.Flink->Blink = Input->ListEntry.Blink; - if( Input->InputEvent.Event.KeyEvent.bKeyDown == TRUE && Input->InputEvent.Event.KeyEvent.uChar.AsciiChar ) - Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar; - else i--; - RtlFreeHeap( CsrssApiHeap, 0, Input ); - } + if( !(Console->ConsoleMode & ENABLE_LINE_INPUT) || Console->WaitingLines ) + for (; iInputEvents.Flink != &Console->InputEvents; i++ ) + { + // remove input event from queue + Input = (ConsoleInput *)Console->InputEvents.Flink; + Input->ListEntry.Blink->Flink = Input->ListEntry.Flink; + Input->ListEntry.Flink->Blink = Input->ListEntry.Blink; + // only pay attention to valid ascii chars, on key down + if( Input->InputEvent.Event.KeyEvent.bKeyDown == TRUE && + Input->InputEvent.Event.KeyEvent.uChar.AsciiChar ) + { + Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar; + // process newline on line buffered mode + if( Console->ConsoleMode & ENABLE_LINE_INPUT && + Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' ) + { + Console->WaitingChars--; + Console->WaitingLines--; + RtlFreeHeap( CsrssApiHeap, 0, Input ); + i++; + break; + } + } + else i--; + Console->WaitingChars--; + RtlFreeHeap( CsrssApiHeap, 0, Input ); + } + Buffer[i] = 0; RtlLeaveCriticalSection( &ActiveConsoleLock ); LpcReply->Data.ReadConsoleReply.NrCharactersRead = i; LpcReply->Status = i ? STATUS_SUCCESS : STATUS_PENDING; @@ -282,7 +300,10 @@ NTSTATUS CsrInitConsole(PCSRSS_PROCESS_DATA ProcessData, Console->CurrentX = 0; Console->CurrentY = 0; Console->ReferenceCount = 0; + Console->WaitingChars = 0; + Console->WaitingLines = 0; Console->Type = CSRSS_CONSOLE_MAGIC; + Console->ConsoleMode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT; Console->Buffer = RtlAllocateHeap( CsrssApiHeap, 0, Console->MaxX * Console->MaxY * 2 ); if( Console->Buffer == 0 ) return STATUS_INSUFFICIENT_RESOURCES; @@ -486,6 +507,7 @@ VOID Console_Api( DWORD RefreshEvent ) IO_STATUS_BLOCK Iosb; NTSTATUS Status; HANDLE Events[2]; // 0 = keyboard, 1 = refresh + int c; Events[0] = 0; Status = NtCreateEvent( &Events[0], STANDARD_RIGHTS_ALL, NULL, FALSE, FALSE ); @@ -586,11 +608,48 @@ VOID Console_Api( DWORD RefreshEvent ) RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); continue; } + // echo to screen if enabled, but do not echo '\b' if there are no keys in buffer to delete + if( ActiveConsole->ConsoleMode & ENABLE_ECHO_INPUT && + KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE && + KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar && + ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\b' || + ActiveConsole->InputEvents.Flink != &ActiveConsole->InputEvents ) ) + { + CsrpWriteConsole( ActiveConsole, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE ); + } + // process special keys if enabled + if( ActiveConsole->ConsoleMode & ENABLE_PROCESSED_INPUT ) + switch( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar ) + { + case '\b': + if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) + for( c = 0; c < 2; c++ ) + { + ConsoleInput *Input = ActiveConsole->InputEvents.Blink; + + CHECKPOINT1; + ActiveConsole->InputEvents.Blink->Blink->Flink = &ActiveConsole->InputEvents; + ActiveConsole->InputEvents.Blink = ActiveConsole->InputEvents.Blink->Blink; + RtlFreeHeap( CsrssApiHeap, 0, Input ); + } + RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); + RtlLeaveCriticalSection( &ActiveConsoleLock ); + continue; + } + // add event to the queue KeyEventRecord->ListEntry.Flink = &ActiveConsole->InputEvents; KeyEventRecord->ListEntry.Blink = ActiveConsole->InputEvents.Blink; ActiveConsole->InputEvents.Blink->Flink = &KeyEventRecord->ListEntry; ActiveConsole->InputEvents.Blink = &KeyEventRecord->ListEntry; - NtSetEvent( ActiveConsole->ActiveEvent, 0 ); + // if line input mode is enabled, only wake the client on enter key up + if( !(ActiveConsole->ConsoleMode & ENABLE_LINE_INPUT ) || + ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' && + KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == FALSE ) ) + { + NtSetEvent( ActiveConsole->ActiveEvent, 0 ); + ActiveConsole->WaitingLines++; + } + ActiveConsole->WaitingChars++; RtlLeaveCriticalSection( &ActiveConsoleLock ); } } @@ -713,6 +772,7 @@ NTSTATUS CsrFillOutputChar( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST if( Console == ActiveConsole ) CsrDrawConsole( Console ); RtlLeaveCriticalSection( &ActiveConsoleLock ); + return Reply->Status; } NTSTATUS CsrReadInputEvent( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST Request, PCSRSS_API_REPLY Reply ) @@ -735,12 +795,19 @@ NTSTATUS CsrReadInputEvent( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST return Status; } RtlEnterCriticalSection( &ActiveConsoleLock ); - if( Console->InputEvents.Flink != &Console->InputEvents ) + // only get input if there is input, and we are not in line input mode, or if we are, if we have a whole line + if( Console->InputEvents.Flink != &Console->InputEvents && + ( !Console->ConsoleMode & ENABLE_LINE_INPUT || Console->WaitingLines ) ) { Input = (ConsoleInput *)Console->InputEvents.Flink; Input->ListEntry.Blink->Flink = Input->ListEntry.Flink; Input->ListEntry.Flink->Blink = Input->ListEntry.Blink; Reply->Data.ReadInputReply.Input = Input->InputEvent; + if( Console->ConsoleMode & ENABLE_LINE_INPUT && + Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE && + Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' ) + Console->WaitingLines--; + Console->WaitingChars--; RtlFreeHeap( CsrssApiHeap, 0, Input ); Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents) ? TRUE : FALSE; Status = STATUS_SUCCESS; @@ -914,6 +981,56 @@ NTSTATUS CsrSetTextAttrib( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST R return Reply->Status = STATUS_SUCCESS; } +NTSTATUS CsrSetConsoleMode( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST Request, PCSRSS_API_REPLY Reply ) +{ + NTSTATUS Status; + PCSRSS_CONSOLE Console; + + Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY); + Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER); + if( Request->Data.SetConsoleModeRequest.Mode & (~CONSOLE_MODE_VALID) || + ( Request->Data.SetConsoleModeRequest.Mode & (ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) && + !( Request->Data.SetConsoleModeRequest.Mode & ENABLE_LINE_INPUT ) ) ) + { + Reply->Status = STATUS_INVALID_PARAMETER; + return Reply->Status; + } + Status = CsrGetObject( ProcessData, Request->Data.SetConsoleModeRequest.ConsoleHandle, (Object_t **)&Console ); + if( !NT_SUCCESS( Status ) ) + { + Reply->Status = Status; + return Status; + } + RtlEnterCriticalSection( &ActiveConsoleLock ); + Console->ConsoleMode = Request->Data.SetConsoleModeRequest.Mode; + RtlLeaveCriticalSection( &ActiveConsoleLock ); + Reply->Status = STATUS_SUCCESS; + return Reply->Status; +} + +NTSTATUS CsrGetConsoleMode( PCSRSS_PROCESS_DATA ProcessData, PCSRSS_API_REQUEST Request, PCSRSS_API_REPLY Reply ) +{ + NTSTATUS Status; + PCSRSS_CONSOLE Console; + + Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY); + Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER); + Status = CsrGetObject( ProcessData, Request->Data.GetConsoleModeRequest.ConsoleHandle, (Object_t **)&Console ); + if( !NT_SUCCESS( Status ) ) + { + Reply->Status = Status; + return Status; + } + RtlEnterCriticalSection( &ActiveConsoleLock ); + Reply->Data.GetConsoleModeReply.ConsoleMode = Console->ConsoleMode; + RtlLeaveCriticalSection( &ActiveConsoleLock ); + Reply->Status = STATUS_SUCCESS; + return Reply->Status; +} + + + + diff --git a/reactos/subsys/csrss/api/wapi.c b/reactos/subsys/csrss/api/wapi.c index b586bcffb69..23bc8976894 100644 --- a/reactos/subsys/csrss/api/wapi.c +++ b/reactos/subsys/csrss/api/wapi.c @@ -1,4 +1,4 @@ -/* $Id: wapi.c,v 1.8 2000/05/26 05:40:20 phreak Exp $ +/* $Id: wapi.c,v 1.9 2000/07/11 04:09:25 phreak Exp $ * * reactos/subsys/csrss/api/wapi.c * @@ -42,6 +42,8 @@ static const CsrFunc CsrFuncs[] = { CsrGetCursorInfo, CsrSetCursorInfo, CsrSetTextAttrib, + CsrGetConsoleMode, + CsrSetConsoleMode, 0 }; static void Thread_Api2(HANDLE ServerPort)