3 * reactos/subsys/csrss/api/conio.c
5 * Console I/O functions
7 * ReactOS Operating System
10 /* INCLUDES ******************************************************************/
12 #include <ddk/ntddk.h>
14 #include <csrss/csrss.h>
16 #include <ntdll/rtl.h>
17 #include <ddk/ntddblue.h>
22 #define LOCK RtlEnterCriticalSection(&ActiveConsoleLock)
23 #define UNLOCK RtlLeaveCriticalSection(&ActiveConsoleLock)
25 /* FIXME: Is there a way to create real aliasses with gcc? [CSH] */
26 #define ALIAS(Name, Target) typeof(Target) Name = Target
29 /* GLOBALS *******************************************************************/
31 static HANDLE ConsoleDeviceHandle;
32 static HANDLE KeyboardDeviceHandle;
33 static PCSRSS_CONSOLE ActiveConsole;
34 CRITICAL_SECTION ActiveConsoleLock;
35 static COORD PhysicalConsoleSize;
37 /* FUNCTIONS *****************************************************************/
39 CSR_API(CsrAllocConsole)
41 PCSRSS_CONSOLE Console;
46 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
47 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
50 if (ProcessData == NULL)
52 return(Reply->Status = STATUS_INVALID_PARAMETER);
55 if( ProcessData->Console )
57 Reply->Status = STATUS_INVALID_PARAMETER;
58 return STATUS_INVALID_PARAMETER;
60 Reply->Status = STATUS_SUCCESS;
61 Console = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_CONSOLE ) );
64 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
65 return STATUS_INSUFFICIENT_RESOURCES;
67 Reply->Status = CsrInitConsole( Console );
68 if( !NT_SUCCESS( Reply->Status ) )
70 RtlFreeHeap( CsrssApiHeap, 0, Console );
73 ProcessData->Console = Console;
74 /* add a reference count because the process is tied to the console */
75 Console->Header.ReferenceCount++;
76 Status = CsrInsertObject( ProcessData, &Reply->Data.AllocConsoleReply.InputHandle, &Console->Header );
77 if( !NT_SUCCESS( Status ) )
79 CsrDeleteConsole( Console );
80 ProcessData->Console = 0;
81 return Reply->Status = Status;
83 Status = CsrInsertObject( ProcessData, &Reply->Data.AllocConsoleReply.OutputHandle, &Console->ActiveBuffer->Header );
84 if( !NT_SUCCESS( Status ) )
86 Console->Header.ReferenceCount--;
87 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
88 ProcessData->Console = 0;
89 return Reply->Status = Status;
91 ClientId.UniqueProcess = (HANDLE)ProcessData->ProcessId;
92 Status = NtOpenProcess( &Process, PROCESS_DUP_HANDLE, 0, &ClientId );
93 if( !NT_SUCCESS( Status ) )
95 DbgPrint( "CSR: NtOpenProcess() failed for handle duplication\n" );
96 Console->Header.ReferenceCount--;
97 ProcessData->Console = 0;
98 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.OutputHandle );
99 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
100 Reply->Status = Status;
103 Status = NtDuplicateObject( NtCurrentProcess(), ProcessData->Console->ActiveEvent, Process, &ProcessData->ConsoleEvent, SYNCHRONIZE, FALSE, 0 );
104 if( !NT_SUCCESS( Status ) )
106 DbgPrint( "CSR: NtDuplicateObject() failed: %x\n", Status );
108 Console->Header.ReferenceCount--;
109 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.OutputHandle );
110 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
111 ProcessData->Console = 0;
112 Reply->Status = Status;
116 return STATUS_SUCCESS;
119 CSR_API(CsrFreeConsole)
121 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
122 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
125 if (ProcessData == NULL)
127 return(Reply->Status = STATUS_INVALID_PARAMETER);
130 Reply->Status = STATUS_NOT_IMPLEMENTED;
132 return(STATUS_NOT_IMPLEMENTED);
135 CSR_API(CsrReadConsole)
137 PLIST_ENTRY CurrentEntry;
141 ULONG nNumberOfCharsToRead;
142 PCSRSS_CONSOLE Console;
145 /* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
146 nNumberOfCharsToRead = Request->Data.ReadConsoleRequest.NrCharactersToRead > CSRSS_MAX_READ_CONSOLE_REQUEST ? CSRSS_MAX_READ_CONSOLE_REQUEST : Request->Data.ReadConsoleRequest.NrCharactersToRead;
147 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
148 Reply->Header.DataSize = Reply->Header.MessageSize -
151 Buffer = Reply->Data.ReadConsoleReply.Buffer;
153 Status = CsrGetObject( ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle, (Object_t **)&Console );
154 if( !NT_SUCCESS( Status ) )
156 Reply->Status = Status;
160 if( Console->Header.Type != CSRSS_CONSOLE_MAGIC )
162 Reply->Status = STATUS_INVALID_HANDLE;
164 return STATUS_INVALID_HANDLE;
166 Reply->Data.ReadConsoleReply.EventHandle = ProcessData->ConsoleEvent;
167 for (; i<nNumberOfCharsToRead && Console->InputEvents.Flink != &Console->InputEvents; i++ )
169 // remove input event from queue
170 CurrentEntry = RemoveHeadList(&Console->InputEvents);
171 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
173 // only pay attention to valid ascii chars, on key down
174 if( Input->InputEvent.EventType == KEY_EVENT &&
175 Input->InputEvent.Event.KeyEvent.bKeyDown == TRUE &&
176 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar )
178 // backspace handling
179 if( Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' )
181 // echo if it has not already been done, and either we or the client has chars to be deleted
182 if( !Input->Echoed && ( i || Request->Data.ReadConsoleRequest.nCharsCanBeDeleted ) )
183 CsrpWriteConsole( Console->ActiveBuffer, &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
185 i-=2; // if we already have something to return, just back it up by 2
187 { // otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer
188 Reply->Data.ReadConsoleReply.NrCharactersRead = 0;
189 Reply->Status = STATUS_NOTIFY_CLEANUP;
190 Console->WaitingChars--;
191 RtlFreeHeap( CsrssApiHeap, 0, Input );
193 return STATUS_NOTIFY_CLEANUP;
195 Request->Data.ReadConsoleRequest.nCharsCanBeDeleted--;
196 Input->Echoed = TRUE; // mark as echoed so we don't echo it below
198 // do not copy backspace to buffer
199 else Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar;
200 // echo to screen if enabled and we did not already echo the char
201 if( Console->Mode & ENABLE_ECHO_INPUT &&
203 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
204 CsrpWriteConsole( Console->ActiveBuffer, &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
207 Console->WaitingChars--;
208 RtlFreeHeap( CsrssApiHeap, 0, Input );
210 Reply->Data.ReadConsoleReply.NrCharactersRead = i;
212 Reply->Status = STATUS_PENDING; // we didn't read anything
213 else if( Console->Mode & ENABLE_LINE_INPUT )
214 if( !Console->WaitingLines || Buffer[i-1] != '\n' )
216 Reply->Status = STATUS_PENDING; // line buffered, didn't get a complete line
219 Console->WaitingLines--;
220 Reply->Status = STATUS_SUCCESS; // line buffered, did get a complete line
222 else Reply->Status = STATUS_SUCCESS; // not line buffered, did read something
223 if( Reply->Status == STATUS_PENDING )
225 Console->EchoCount = nNumberOfCharsToRead - i;
228 Console->EchoCount = 0; // if the client is no longer waiting on input, do not echo
230 Reply->Header.MessageSize += i;
232 return Reply->Status;
235 #define GET_CELL_BUFFER(b,o)\
238 #define SET_CELL_BUFFER(b,o,c,a)\
239 (b)->Buffer[(o)++]=(c);\
240 (b)->Buffer[(o)++]=(a);
244 PCSRSS_SCREEN_BUFFER Buff,
248 DWORD Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + StartX);
250 for ( ; StartX < Buff->MaxX; StartX ++ )
252 /* Fill the cell: Offset is incremented by the macro */
253 SET_CELL_BUFFER(Buff,Offset,' ',Buff->DefaultAttrib)
257 NTSTATUS STDCALL CsrpWriteConsole( PCSRSS_SCREEN_BUFFER Buff, CHAR *Buffer, DWORD Length, BOOL Attrib )
259 IO_STATUS_BLOCK Iosb;
264 for( i = 0; i < Length; i++ )
266 switch( Buffer[ i ] )
271 /* slide the viewable screen */
272 if (((Buff->CurrentY-Buff->ShowY + Buff->MaxY) % Buff->MaxY) == PhysicalConsoleSize.Y - 1)
273 if (++Buff->ShowY == Buff->MaxY)
275 if( ++Buff->CurrentY == Buff->MaxY )
279 ClearLineBuffer (Buff, 0);
283 if( Buff->CurrentX == 0 )
285 /* slide viewable screen up */
286 if( Buff->ShowY == Buff->CurrentY )
288 if( Buff->ShowY == 0 )
289 Buff->ShowY = Buff->MaxY;
293 /* slide virtual position up */
294 Buff->CurrentX = Buff->MaxX;
295 if( Buff->CurrentY == 0 )
296 Buff->CurrentY = Buff->MaxY;
302 Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + Buff->CurrentX);
303 SET_CELL_BUFFER(Buff,Offset,' ',Buff->DefaultAttrib);
311 CsrpWriteConsole(Buff, " ", (8 - (Buff->CurrentX % 8)), FALSE);
315 Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
316 Buff->Buffer[Offset ++] = Buffer[ i ];
318 Buff->Buffer[Offset] = Buff->DefaultAttrib;
320 if( Buff->CurrentX == Buff->MaxX )
322 /* if end of line, go to next */
324 if( ++Buff->CurrentY == Buff->MaxY )
326 /* if end of buffer, wrap back to beginning */
330 ClearLineBuffer (Buff, 0);
331 /* slide the viewable screen */
332 if( (Buff->CurrentY - Buff->ShowY + Buff->MaxY - 1) % Buff->MaxY == PhysicalConsoleSize.Y -1)
333 if( ++Buff->ShowY == Buff->MaxY )
338 if( Buff == ActiveConsole->ActiveBuffer )
339 { /* only write to screen if Console is Active, and not scrolled up */
342 Status = NtWriteFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, Buffer, Length, NULL, 0);
343 if (!NT_SUCCESS(Status))
344 DbgPrint("CSR: Write failed\n");
347 return(STATUS_SUCCESS);
350 #define CsrpInitRect(_Rect, _Top, _Left, _Bottom, _Right) \
352 ((_Rect).Top) = _Top; \
353 ((_Rect).Left) = _Left; \
354 ((_Rect).Bottom) = _Bottom; \
355 ((_Rect).Right) = _Right; \
358 #define CsrpRectHeight(Rect) \
359 ((Rect.Top) > (Rect.Bottom) ? 0 : (Rect.Bottom) - (Rect.Top) + 1)
361 #define CsrpRectWidth(Rect) \
362 ((Rect.Left) > (Rect.Right) ? 0 : (Rect.Right) - (Rect.Left) + 1)
364 #define CsrpIsRectEmpty(Rect) \
365 ((Rect.Left > Rect.Right) || (Rect.Top > Rect.Bottom))
368 inline BOOLEAN CsrpIsEqualRect(
372 return ((Rect1.Left == Rect2.Left) && (Rect1.Right == Rect2.Right) &&
373 (Rect1.Top == Rect2.Top) && (Rect1.Bottom == Rect2.Bottom));
376 inline BOOLEAN CsrpGetIntersection(
377 PSMALL_RECT Intersection,
381 if (CsrpIsRectEmpty(Rect1) ||
382 (CsrpIsRectEmpty(Rect2)) ||
383 (Rect1.Top > Rect2.Bottom) ||
384 (Rect1.Left > Rect2.Right) ||
385 (Rect1.Bottom < Rect2.Top) ||
386 (Rect1.Right < Rect2.Left))
388 /* The rectangles do not intersect */
389 CsrpInitRect(*Intersection, 0, -1, 0, -1)
395 RtlMax(Rect1.Top, Rect2.Top),
396 RtlMax(Rect1.Left, Rect2.Left),
397 RtlMin(Rect1.Bottom, Rect2.Bottom),
398 RtlMin(Rect1.Right, Rect2.Right));
402 inline BOOLEAN CsrpGetUnion(
407 if (CsrpIsRectEmpty(Rect1))
409 if (CsrpIsRectEmpty(Rect2))
411 CsrpInitRect(*Union, 0, -1, 0, -1);
419 if (CsrpIsRectEmpty(Rect2))
427 RtlMin(Rect1.Top, Rect2.Top),
428 RtlMin(Rect1.Left, Rect2.Left),
429 RtlMax(Rect1.Bottom, Rect2.Bottom),
430 RtlMax(Rect1.Right, Rect2.Right));
436 inline BOOLEAN CsrpSubtractRect(
437 PSMALL_RECT Subtraction,
443 if (CsrpIsRectEmpty(Rect1))
445 CsrpInitRect(*Subtraction, 0, -1, 0, -1);
448 *Subtraction = Rect1;
449 if (CsrpGetIntersection(&tmp, Rect1, Rect2))
451 if (CsrpIsEqualRect(tmp, *Subtraction))
453 CsrpInitRect(*Subtraction, 0, -1, 0, -1);
456 if ((tmp.Top == Subtraction->Top) && (tmp.Bottom == Subtraction->Bottom))
458 if (tmp.Left == Subtraction->Left)
459 Subtraction->Left = tmp.Right;
460 else if (tmp.Right == Subtraction->Right)
461 Subtraction->Right = tmp.Left;
463 else if ((tmp.Left == Subtraction->Left) && (tmp.Right == Subtraction->Right))
465 if (tmp.Top == Subtraction->Top)
466 Subtraction->Top = tmp.Bottom;
467 else if (tmp.Bottom == Subtraction->Bottom)
468 Subtraction->Bottom = tmp.Top;
475 * Screen buffer must be locked when this function is called
477 static VOID CsrpCopyRegion(
478 PCSRSS_SCREEN_BUFFER ScreenBuffer,
479 SMALL_RECT SrcRegion,
480 SMALL_RECT DstRegion)
488 DstY = DstRegion.Top;
489 BytesPerLine = CsrpRectWidth(DstRegion) * 2;
491 SrcY = (SrcRegion.Top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
492 DstY = (DstRegion.Top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
493 SrcOffset = (SrcY * ScreenBuffer->MaxX + SrcRegion.Left + ScreenBuffer->ShowX) * 2;
494 DstOffset = (DstY * ScreenBuffer->MaxX + DstRegion.Left + ScreenBuffer->ShowX) * 2;
496 for (i = SrcRegion.Top; i <= SrcRegion.Bottom; i++)
499 &ScreenBuffer->Buffer[DstOffset],
500 &ScreenBuffer->Buffer[SrcOffset],
503 if (++DstY == ScreenBuffer->MaxY)
506 DstOffset = (DstRegion.Left + ScreenBuffer->ShowX) * 2;
510 DstOffset += ScreenBuffer->MaxX * 2;
513 if (++SrcY == ScreenBuffer->MaxY)
516 SrcOffset = (SrcRegion.Left + ScreenBuffer->ShowX) * 2;
520 SrcOffset += ScreenBuffer->MaxX * 2;
526 * Screen buffer must be locked when this function is called
528 static VOID CsrpFillRegion(
529 PCSRSS_SCREEN_BUFFER ScreenBuffer,
538 Y = (Region.Top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
539 Offset = (Y * ScreenBuffer->MaxX + Region.Left + ScreenBuffer->ShowX) * 2;
540 Delta = (ScreenBuffer->MaxX - CsrpRectWidth(Region)) * 2;
542 for (i = Region.Top; i <= Region.Bottom; i++)
544 for (X = Region.Left; X <= Region.Right; X++)
546 SET_CELL_BUFFER(ScreenBuffer, Offset, CharInfo.Char.AsciiChar, CharInfo.Attributes);
548 if (++Y == ScreenBuffer->MaxY)
551 Offset = (Region.Left + ScreenBuffer->ShowX) * 2;
561 * Screen buffer must be locked when this function is called
563 inline NTSTATUS CsrpSetConsoleDeviceCursor(PCSRSS_SCREEN_BUFFER ScreenBuffer, SHORT X, SHORT Y)
565 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
566 IO_STATUS_BLOCK Iosb;
568 ScrInfo.dwCursorPosition.X = X;
569 ScrInfo.dwCursorPosition.Y = Y;
570 ScrInfo.wAttributes = ScreenBuffer->DefaultAttrib;
572 return NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
573 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
577 * Region - Region of virtual screen buffer to draw onto the physical console
578 * Screen buffer must be locked when this function is called
580 static VOID CsrpDrawRegion(
581 PCSRSS_SCREEN_BUFFER ScreenBuffer,
584 IO_STATUS_BLOCK Iosb;
586 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
593 Mode.dwMode = 0; /* clear ENABLE_PROCESSED_OUTPUT mode */
594 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
595 IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
596 if( !NT_SUCCESS( Status ) )
598 DbgPrint( "CSR: Failed to set console mode\n" );
602 /* blast out buffer */
603 BytesPerLine = CsrpRectWidth(Region) * 2;
604 SrcOffset = (((Region.Top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY) * ScreenBuffer->MaxX + Region.Left + ScreenBuffer->ShowX) * 2;
605 SrcDelta = ScreenBuffer->MaxX * 2;
606 for( i = Region.Top, y = ScreenBuffer->ShowY; i <= Region.Bottom; i++ )
608 /* Position the cursor correctly */
609 Status = CsrpSetConsoleDeviceCursor(ScreenBuffer, Region.Left, i);
610 if( !NT_SUCCESS( Status ) )
612 DbgPrint( "CSR: Failed to set console info\n" );
616 Status = NtWriteFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
617 &ScreenBuffer->Buffer[ SrcOffset ],
618 BytesPerLine, 0, 0 );
619 if( !NT_SUCCESS( Status ) )
621 DbgPrint( "CSR: Write to console failed\n" );
625 /* wrap back around the end of the buffer */
626 if( ++y == ScreenBuffer->MaxY )
629 SrcOffset = (Region.Left + ScreenBuffer->ShowX) * 2;
633 SrcOffset += SrcDelta;
636 Mode.dwMode = ENABLE_PROCESSED_OUTPUT;
637 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
638 IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
639 if( !NT_SUCCESS( Status ) )
641 DbgPrint( "CSR: Failed to set console mode\n" );
644 Status = CsrpSetConsoleDeviceCursor(
646 ScreenBuffer->CurrentX - ScreenBuffer->ShowX,
647 ((ScreenBuffer->CurrentY + ScreenBuffer->MaxY) - ScreenBuffer->ShowY) % ScreenBuffer->MaxY);
648 if( !NT_SUCCESS( Status ) )
650 DbgPrint( "CSR: Failed to set console info\n" );
653 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
654 IOCTL_CONSOLE_SET_CURSOR_INFO, &ScreenBuffer->CursorInfo,
655 sizeof( ScreenBuffer->CursorInfo ), 0, 0 );
656 if( !NT_SUCCESS( Status ) )
658 DbgPrint( "CSR: Failed to set cursor info\n" );
664 CSR_API(CsrWriteConsole)
666 BYTE *Buffer = Request->Data.WriteConsoleRequest.Buffer;
667 PCSRSS_SCREEN_BUFFER Buff;
669 DPRINT("CsrWriteConsole\n");
671 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
672 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
676 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle,
677 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
680 return Reply->Status = STATUS_INVALID_HANDLE;
682 CsrpWriteConsole( Buff, Buffer, Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE );
684 return Reply->Status = STATUS_SUCCESS;
688 NTSTATUS STDCALL CsrInitConsoleScreenBuffer( PCSRSS_SCREEN_BUFFER Console )
690 Console->Header.Type = CSRSS_SCREEN_BUFFER_MAGIC;
691 Console->Header.ReferenceCount = 0;
692 Console->MaxX = PhysicalConsoleSize.X;
693 Console->MaxY = PhysicalConsoleSize.Y;
696 Console->CurrentX = 0;
697 Console->CurrentY = 0;
698 Console->Buffer = RtlAllocateHeap( CsrssApiHeap, 0, Console->MaxX * Console->MaxY * 2 );
699 if( Console->Buffer == 0 )
700 return STATUS_INSUFFICIENT_RESOURCES;
701 Console->DefaultAttrib = 0x17;
702 /* initialize buffer to be empty with default attributes */
703 for( ; Console->CurrentY < Console->MaxY; Console->CurrentY++ )
705 ClearLineBuffer (Console, 0);
707 Console->CursorInfo.bVisible = TRUE;
708 Console->CursorInfo.dwSize = 5;
709 Console->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
710 Console->CurrentX = 0;
711 Console->CurrentY = 0;
712 return STATUS_SUCCESS;
715 VOID STDCALL CsrDeleteScreenBuffer( PCSRSS_SCREEN_BUFFER Buffer )
717 RtlFreeHeap( CsrssApiHeap, 0, Buffer->Buffer );
718 RtlFreeHeap( CsrssApiHeap, 0, Buffer );
721 NTSTATUS STDCALL CsrInitConsole(PCSRSS_CONSOLE Console)
724 OBJECT_ATTRIBUTES ObjectAttributes;
726 Console->Title.MaximumLength = Console->Title.Length = 0;
727 Console->Title.Buffer = 0;
729 RtlCreateUnicodeString( &Console->Title, L"Command Prompt" );
731 Console->Header.ReferenceCount = 0;
732 Console->WaitingChars = 0;
733 Console->WaitingLines = 0;
734 Console->EchoCount = 0;
735 Console->Header.Type = CSRSS_CONSOLE_MAGIC;
736 Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
737 Console->EarlyReturn = FALSE;
738 InitializeListHead(&Console->InputEvents);
740 InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_INHERIT, NULL, NULL);
742 Status = NtCreateEvent( &Console->ActiveEvent, STANDARD_RIGHTS_ALL, &ObjectAttributes, FALSE, FALSE );
743 if( !NT_SUCCESS( Status ) )
747 Console->ActiveBuffer = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
748 if( !Console->ActiveBuffer )
750 NtClose( Console->ActiveEvent );
751 return STATUS_INSUFFICIENT_RESOURCES;
753 Status = CsrInitConsoleScreenBuffer( Console->ActiveBuffer );
754 if( !NT_SUCCESS( Status ) )
756 NtClose( Console->ActiveEvent );
757 RtlFreeHeap( CsrssApiHeap, 0, Console->ActiveBuffer );
760 /* add a reference count because the buffer is tied to the console */
761 Console->ActiveBuffer->Header.ReferenceCount++;
762 /* make console active, and insert into console list */
766 Console->Prev = ActiveConsole;
767 Console->Next = ActiveConsole->Next;
768 ActiveConsole->Next->Prev = Console;
769 ActiveConsole->Next = Console;
772 Console->Prev = Console;
773 Console->Next = Console;
775 ActiveConsole = Console;
776 /* copy buffer contents to screen */
777 CsrDrawConsole( Console->ActiveBuffer );
779 return STATUS_SUCCESS;
782 /***************************************************************
783 * CsrDrawConsole blasts the console buffer onto the screen *
784 * must be called while holding the active console lock *
785 **************************************************************/
786 VOID STDCALL CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff )
794 PhysicalConsoleSize.Y - 1,
795 PhysicalConsoleSize.X - 1);
797 CsrpDrawRegion(Buff, Region);
801 VOID STDCALL CsrDeleteConsole( PCSRSS_CONSOLE Console )
804 DPRINT( "CsrDeleteConsole\n" );
806 /* Drain input event queue */
807 while( Console->InputEvents.Flink != &Console->InputEvents )
809 Event = (ConsoleInput *)Console->InputEvents.Flink;
810 Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
811 Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
812 RtlFreeHeap( CsrssApiHeap, 0, Event );
814 /* Switch to next console */
815 if( ActiveConsole == Console )
817 if( Console->Next != Console )
819 ActiveConsole = Console->Next;
821 else ActiveConsole = 0;
823 if (Console->Next != Console)
825 Console->Prev->Next = Console->Next;
826 Console->Next->Prev = Console->Prev;
830 CsrDrawConsole( ActiveConsole->ActiveBuffer );
831 if( !--Console->ActiveBuffer->Header.ReferenceCount )
832 CsrDeleteScreenBuffer( Console->ActiveBuffer );
834 NtClose( Console->ActiveEvent );
835 RtlFreeUnicodeString( &Console->Title );
836 RtlFreeHeap( CsrssApiHeap, 0, Console );
839 VOID STDCALL CsrInitConsoleSupport(VOID)
841 OBJECT_ATTRIBUTES ObjectAttributes;
842 UNICODE_STRING DeviceName;
844 IO_STATUS_BLOCK Iosb;
845 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
847 DPRINT("CSR: CsrInitConsoleSupport()\n");
849 RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\BlueScreen");
850 InitializeObjectAttributes(&ObjectAttributes,
855 Status = NtOpenFile(&ConsoleDeviceHandle,
860 FILE_SYNCHRONOUS_IO_ALERT);
861 if (!NT_SUCCESS(Status))
863 DbgPrint("CSR: Failed to open console. Expect problems.\n");
866 RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\Keyboard");
867 InitializeObjectAttributes(&ObjectAttributes,
872 Status = NtOpenFile(&KeyboardDeviceHandle,
878 if (!NT_SUCCESS(Status))
880 DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
884 RtlInitializeCriticalSection( &ActiveConsoleLock );
885 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, &ScrInfo, sizeof( ScrInfo ) );
886 if( !NT_SUCCESS( Status ) )
888 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
891 PhysicalConsoleSize = ScrInfo.dwSize;
894 VOID Console_Api( DWORD RefreshEvent )
896 /* keep reading events from the keyboard and stuffing them into the current
897 console's input queue */
898 ConsoleInput *KeyEventRecord;
899 ConsoleInput *TempInput;
900 IO_STATUS_BLOCK Iosb;
902 HANDLE Events[2]; // 0 = keyboard, 1 = refresh
905 PCSRSS_CONSOLE SwapConsole = 0; // console we are thinking about swapping with
908 Status = NtCreateEvent( &Events[0], STANDARD_RIGHTS_ALL, NULL, FALSE, FALSE );
909 if( !NT_SUCCESS( Status ) )
911 DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status );
912 NtTerminateProcess( NtCurrentProcess(), Status );
914 Events[1] = (HANDLE)RefreshEvent;
917 KeyEventRecord = RtlAllocateHeap(CsrssApiHeap,
919 sizeof(ConsoleInput));
920 if ( KeyEventRecord == 0 )
922 DbgPrint( "CSR: Memory allocation failure!" );
925 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
926 Status = NtReadFile( KeyboardDeviceHandle, Events[0], NULL, NULL, &Iosb,
927 &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 );
928 if( !NT_SUCCESS( Status ) )
930 DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
931 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
934 if( Status == STATUS_PENDING )
938 Status = NtWaitForMultipleObjects( 2, Events, WaitAny, FALSE, NULL );
939 if( Status == STATUS_WAIT_0 + 1 )
942 CsrDrawConsole( ActiveConsole->ActiveBuffer );
946 else if( Status != STATUS_WAIT_0 )
948 DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status );
949 NtTerminateProcess( NtCurrentProcess(), Status );
954 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
955 ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED )&&
956 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_TAB )
957 if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
963 /* alt-tab, swap consoles */
964 // move SwapConsole to next console, and print its title
967 SwapConsole = ActiveConsole;
969 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED )
970 SwapConsole = SwapConsole->Prev;
971 else SwapConsole = SwapConsole->Next;
972 Title.MaximumLength = RtlUnicodeStringToAnsiSize( &SwapConsole->Title );
974 Buffer = RtlAllocateHeap( CsrssApiHeap,
976 sizeof( COORD ) + Title.MaximumLength);
977 pos = (COORD *)Buffer;
978 Title.Buffer = Buffer + sizeof( COORD );
980 RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Title, FALSE);
981 pos->Y = PhysicalConsoleSize.Y / 2;
982 pos->X = ( PhysicalConsoleSize.X - Title.Length ) / 2;
983 // redraw the console to clear off old title
984 CsrDrawConsole( ActiveConsole->ActiveBuffer );
985 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
990 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
992 sizeof (COORD) + Title.Length,
995 if( !NT_SUCCESS( Status ) )
997 DPRINT1( "Error writing to console\n" );
999 RtlFreeHeap( CsrssApiHeap, 0, Buffer );
1002 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1006 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1009 else if( SwapConsole &&
1010 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_MENU &&
1011 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == FALSE )
1013 // alt key released, swap consoles
1017 if( SwapConsole != ActiveConsole )
1019 // first remove swapconsole from the list
1020 SwapConsole->Prev->Next = SwapConsole->Next;
1021 SwapConsole->Next->Prev = SwapConsole->Prev;
1022 // now insert before activeconsole
1023 SwapConsole->Next = ActiveConsole;
1024 SwapConsole->Prev = ActiveConsole->Prev;
1025 ActiveConsole->Prev->Next = SwapConsole;
1026 ActiveConsole->Prev = SwapConsole;
1028 ActiveConsole = SwapConsole;
1030 CsrDrawConsole( ActiveConsole->ActiveBuffer );
1034 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
1035 ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) &&
1036 ( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP ||
1037 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) )
1039 if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
1041 /* scroll up or down */
1043 if( ActiveConsole == 0 )
1045 DbgPrint( "CSR: No Active Console!\n" );
1047 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1050 if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP )
1052 /* only scroll up if there is room to scroll up into */
1053 if( ActiveConsole->ActiveBuffer->ShowY != ((ActiveConsole->ActiveBuffer->CurrentY + 1) %
1054 ActiveConsole->ActiveBuffer->MaxY) )
1055 ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY +
1056 ActiveConsole->ActiveBuffer->MaxY - 1) % ActiveConsole->ActiveBuffer->MaxY;
1058 else if( ActiveConsole->ActiveBuffer->ShowY != ActiveConsole->ActiveBuffer->CurrentY )
1059 /* only scroll down if there is room to scroll down into */
1060 if( ActiveConsole->ActiveBuffer->ShowY % ActiveConsole->ActiveBuffer->MaxY !=
1061 ActiveConsole->ActiveBuffer->CurrentY )
1063 if( ((ActiveConsole->ActiveBuffer->CurrentY + 1) % ActiveConsole->ActiveBuffer->MaxY) !=
1064 (ActiveConsole->ActiveBuffer->ShowY + PhysicalConsoleSize.Y) % ActiveConsole->ActiveBuffer->MaxY )
1065 ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY + 1) %
1066 ActiveConsole->ActiveBuffer->MaxY;
1067 CsrDrawConsole( ActiveConsole->ActiveBuffer );
1070 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1074 if( ActiveConsole == 0 )
1076 DbgPrint( "CSR: No Active Console!\n" );
1078 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1081 // process special keys if enabled
1082 if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) )
1083 switch( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar )
1086 // add a \n to the queue as well
1088 updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
1089 KeyEventRecord->Echoed = FALSE;
1090 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
1091 InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1092 ActiveConsole->WaitingChars++;
1093 KeyEventRecord = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( ConsoleInput ) );
1094 if( !KeyEventRecord )
1096 DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
1100 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1101 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
1102 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
1103 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
1104 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
1106 // add event to the queue
1107 InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1108 // if line input mode is enabled, only wake the client on enter key down
1109 if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT ) ||
1110 ActiveConsole->EarlyReturn ||
1111 ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' &&
1112 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) )
1114 NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1115 if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1116 ActiveConsole->WaitingLines++;
1118 KeyEventRecord->Echoed = FALSE;
1119 if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) &&
1120 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' &&
1121 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown )
1123 // walk the input queue looking for a char to backspace
1124 for( TempInput = (ConsoleInput *)ActiveConsole->InputEvents.Blink;
1125 TempInput != (ConsoleInput *)&ActiveConsole->InputEvents &&
1126 (TempInput->InputEvent.EventType != KEY_EVENT ||
1127 TempInput->InputEvent.Event.KeyEvent.bKeyDown == FALSE ||
1128 TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' );
1129 TempInput = (ConsoleInput *)TempInput->ListEntry.Blink );
1130 // if we found one, delete it, otherwise, wake the client
1131 if( TempInput != (ConsoleInput *)&ActiveConsole->InputEvents )
1133 // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
1134 RemoveEntryList(&TempInput->ListEntry);
1135 if( TempInput->Echoed )
1136 CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1137 RtlFreeHeap( CsrssApiHeap, 0, TempInput );
1138 RemoveEntryList(&KeyEventRecord->ListEntry);
1139 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1140 ActiveConsole->WaitingChars -= 2;
1142 else NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1145 // echo chars if we are supposed to and client is waiting for some
1146 if( ( ActiveConsole->Mode & ENABLE_ECHO_INPUT ) && ActiveConsole->EchoCount &&
1147 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar &&
1148 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE &&
1149 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
1151 // mark the char as already echoed
1152 CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1153 ActiveConsole->EchoCount--;
1154 KeyEventRecord->Echoed = TRUE;
1157 ActiveConsole->WaitingChars++;
1158 if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT) )
1159 NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1164 CSR_API(CsrGetScreenBufferInfo)
1167 PCSRSS_SCREEN_BUFFER Buff;
1168 PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1169 IO_STATUS_BLOCK Iosb;
1171 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1172 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1173 sizeof(LPC_MESSAGE);
1176 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle,
1177 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1180 return Reply->Status = STATUS_INVALID_HANDLE;
1182 pInfo = &Reply->Data.ScreenBufferInfoReply.Info;
1183 if( Buff == ActiveConsole->ActiveBuffer )
1185 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1186 IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, pInfo, sizeof( *pInfo ) );
1187 if( !NT_SUCCESS( Status ) )
1188 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
1189 Reply->Status = Status;
1192 pInfo->dwSize.X = PhysicalConsoleSize.X;
1193 pInfo->dwSize.Y = PhysicalConsoleSize.Y;
1194 pInfo->dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1195 pInfo->dwCursorPosition.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1196 pInfo->wAttributes = Buff->DefaultAttrib;
1197 pInfo->srWindow.Left = 0;
1198 pInfo->srWindow.Right = PhysicalConsoleSize.X - 1;
1199 pInfo->srWindow.Top = 0;
1200 pInfo->srWindow.Bottom = PhysicalConsoleSize.Y - 1;
1201 Reply->Status = STATUS_SUCCESS;
1204 return Reply->Status;
1207 CSR_API(CsrSetCursor)
1210 PCSRSS_SCREEN_BUFFER Buff;
1211 CONSOLE_SCREEN_BUFFER_INFO Info;
1212 IO_STATUS_BLOCK Iosb;
1214 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1215 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1216 sizeof(LPC_MESSAGE);
1219 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.SetCursorRequest.ConsoleHandle,
1220 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1223 return Reply->Status = STATUS_INVALID_HANDLE;
1225 Info.dwCursorPosition = Request->Data.SetCursorRequest.Position;
1226 Info.wAttributes = Buff->DefaultAttrib;
1227 if( Buff == ActiveConsole->ActiveBuffer )
1229 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1230 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &Info, sizeof( Info ), 0, 0 );
1231 if( !NT_SUCCESS( Status ) )
1232 DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
1235 Buff->CurrentX = Info.dwCursorPosition.X + Buff->ShowX;
1236 Buff->CurrentY = (Info.dwCursorPosition.Y + Buff->ShowY) % Buff->MaxY;
1238 return Reply->Status = Status;
1241 CSR_API(CsrWriteConsoleOutputChar)
1243 PBYTE String = Request->Data.WriteConsoleOutputCharRequest.String;
1245 PCSRSS_SCREEN_BUFFER Buff;
1248 IO_STATUS_BLOCK Iosb;
1250 DPRINT("CsrWriteConsoleOutputChar\n");
1252 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1253 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1254 sizeof(LPC_MESSAGE);
1256 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1259 return Reply->Status = STATUS_INVALID_HANDLE;
1263 X = Request->Data.WriteConsoleOutputCharRequest.Coord.X + Buff->ShowX;
1264 Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1265 Length = Request->Data.WriteConsoleOutputCharRequest.Length;
1266 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1269 *Buffer = *String++;
1271 if (++X == Buff->MaxX)
1273 if (++Y == Buff->MaxY)
1276 Buffer = Buff->Buffer;
1281 if( ActiveConsole->ActiveBuffer == Buff )
1283 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1288 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
1289 &Request->Data.WriteConsoleOutputCharRequest.Coord,
1290 sizeof (COORD) + Request->Data.WriteConsoleOutputCharRequest.Length,
1293 if( !NT_SUCCESS( Status ) )
1294 DPRINT1( "Failed to write output chars: %x\n", Status );
1296 Reply->Data.WriteConsoleOutputCharReply.EndCoord.X = X - Buff->ShowX;
1297 Reply->Data.WriteConsoleOutputCharReply.EndCoord.Y = (Y + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1299 return Reply->Status = STATUS_SUCCESS;
1302 CSR_API(CsrFillOutputChar)
1304 PCSRSS_SCREEN_BUFFER Buff;
1307 OUTPUT_CHARACTER Character;
1310 IO_STATUS_BLOCK Iosb;
1312 DPRINT("CsrFillOutputChar\n");
1314 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1315 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1316 sizeof(LPC_MESSAGE);
1319 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1322 return Reply->Status = STATUS_INVALID_HANDLE;
1324 X = Request->Data.FillOutputRequest.Position.X + Buff->ShowX;
1325 Y = (Request->Data.FillOutputRequest.Position.Y + Buff->ShowY) % Buff->MaxY;
1326 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1327 Char = Request->Data.FillOutputRequest.Char;
1328 Length = Request->Data.FillOutputRequest.Length;
1333 if( ++X == Buff->MaxX )
1335 if( ++Y == Buff->MaxY )
1338 Buffer = Buff->Buffer;
1343 if( Buff == ActiveConsole->ActiveBuffer )
1345 Character.dwCoord = Request->Data.FillOutputRequest.Position;
1346 Character.cCharacter = Char;
1347 Character.nLength = Request->Data.FillOutputRequest.Length;
1348 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1353 IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER,
1358 if (!NT_SUCCESS(Status))
1359 DPRINT1( "Failed to write output characters to console\n" );
1362 return Reply->Status;
1365 CSR_API(CsrReadInputEvent)
1367 PLIST_ENTRY CurrentEntry;
1368 PCSRSS_CONSOLE Console;
1370 ConsoleInput *Input;
1372 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1373 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1374 sizeof(LPC_MESSAGE);
1375 Reply->Data.ReadInputReply.Event = ProcessData->ConsoleEvent;
1378 Status = CsrGetObject( ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, (Object_t **)&Console );
1379 if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? 0 : STATUS_INVALID_HANDLE))
1381 Reply->Status = Status;
1386 // only get input if there is any
1387 if( Console->InputEvents.Flink != &Console->InputEvents )
1389 CurrentEntry = RemoveHeadList(&Console->InputEvents);
1390 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1391 Reply->Data.ReadInputReply.Input = Input->InputEvent;
1393 if( Input->InputEvent.EventType == KEY_EVENT )
1395 if( Console->Mode & ENABLE_LINE_INPUT &&
1396 Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE &&
1397 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1398 Console->WaitingLines--;
1399 Console->WaitingChars--;
1401 RtlFreeHeap( CsrssApiHeap, 0, Input );
1403 if (Console->InputEvents.Flink != &Console->InputEvents &&
1404 Reply->Data.ReadInputReply.Input.EventType == KEY_EVENT &&
1405 Reply->Data.ReadInputReply.Input.Event.KeyEvent.uChar.AsciiChar == '\r')
1407 Input = CONTAINING_RECORD(Console->InputEvents.Flink, ConsoleInput, ListEntry);
1408 if (Input->InputEvent.EventType == KEY_EVENT &&
1409 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' &&
1410 ((Input->InputEvent.Event.KeyEvent.bKeyDown && Reply->Data.ReadInputReply.Input.Event.KeyEvent.bKeyDown) ||
1411 (Input->InputEvent.Event.KeyEvent.bKeyDown==FALSE && Reply->Data.ReadInputReply.Input.Event.KeyEvent.bKeyDown==FALSE)))
1413 if(Console->Mode & ENABLE_LINE_INPUT &&
1414 Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE &&
1415 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1416 Console->WaitingLines--;
1417 Console->WaitingChars--;
1418 RemoveHeadList(&Console->InputEvents);
1419 RtlFreeHeap( CsrssApiHeap, 0, Input );
1423 Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents) ? TRUE : FALSE;
1424 Status = STATUS_SUCCESS;
1425 Console->EarlyReturn = FALSE; // clear early return
1428 Status = STATUS_PENDING;
1429 Console->EarlyReturn = TRUE; // mark for early return
1432 return Reply->Status = Status;
1435 CSR_API(CsrWriteConsoleOutputAttrib)
1437 PCSRSS_SCREEN_BUFFER Buff;
1438 PUCHAR Buffer, Attribute;
1441 IO_STATUS_BLOCK Iosb;
1443 DPRINT("CsrWriteConsoleOutputAttrib\n");
1445 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1446 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1447 sizeof(LPC_MESSAGE);
1449 Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1450 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1452 Reply->Status = Status;
1456 X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X + Buff->ShowX;
1457 Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1458 Length = Request->Data.WriteConsoleOutputAttribRequest.Length;
1459 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
1460 Attribute = Request->Data.WriteConsoleOutputAttribRequest.String;
1463 *Buffer = *Attribute++;
1465 if( ++X == Buff->MaxX )
1468 if( ++Y == Buff->MaxY )
1471 Buffer = Buff->Buffer + 1;
1475 if( Buff == ActiveConsole->ActiveBuffer )
1477 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1482 IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE,
1483 &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1484 Request->Data.WriteConsoleOutputAttribRequest.Length +
1488 if( !NT_SUCCESS( Status ) )
1489 DPRINT1( "Failed to write output attributes to console\n" );
1491 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1492 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.Y = ( Buff->CurrentY + Buff->MaxY - Buff->ShowY ) % Buff->MaxY;
1494 return Reply->Status = STATUS_SUCCESS;
1497 CSR_API(CsrFillOutputAttrib)
1499 OUTPUT_ATTRIBUTE Attribute;
1500 PCSRSS_SCREEN_BUFFER Buff;
1504 IO_STATUS_BLOCK Iosb;
1507 DPRINT("CsrFillOutputAttrib\n");
1509 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1510 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1511 sizeof(LPC_MESSAGE);
1513 Status = CsrGetObject( ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1514 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1516 Reply->Status = Status;
1520 X = Request->Data.FillOutputAttribRequest.Coord.X + Buff->ShowX;
1521 Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1522 Length = Request->Data.FillOutputAttribRequest.Length;
1523 Attr = Request->Data.FillOutputAttribRequest.Attribute;
1524 Buffer = &Buff->Buffer[(Y * Buff->MaxX * 2) + (X * 2) + 1];
1529 if( ++X == Buff->MaxX )
1532 if( ++Y == Buff->MaxY )
1535 Buffer = Buff->Buffer + 1;
1539 if( Buff == ActiveConsole->ActiveBuffer )
1541 Attribute.wAttribute = Attr;
1542 Attribute.nLength = Request->Data.FillOutputAttribRequest.Length;
1543 Attribute.dwCoord = Request->Data.FillOutputAttribRequest.Coord;
1544 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1549 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE,
1551 sizeof(OUTPUT_ATTRIBUTE),
1554 if( !NT_SUCCESS( Status ) )
1555 DPRINT1( "Failed to fill output attributes to console\n" );
1558 return Reply->Status = STATUS_SUCCESS;
1562 CSR_API(CsrGetCursorInfo)
1564 PCSRSS_SCREEN_BUFFER Buff;
1567 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1568 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1569 sizeof(LPC_MESSAGE);
1571 Status = CsrGetObject( ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1572 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1574 Reply->Status = Status;
1578 Reply->Data.GetCursorInfoReply.Info = Buff->CursorInfo;
1580 return Reply->Status = STATUS_SUCCESS;
1583 CSR_API(CsrSetCursorInfo)
1585 PCSRSS_SCREEN_BUFFER Buff;
1587 IO_STATUS_BLOCK Iosb;
1589 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1590 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1591 sizeof(LPC_MESSAGE);
1593 Status = CsrGetObject( ProcessData,
1594 Request->Data.SetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1596 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1598 Reply->Status = Status;
1602 Buff->CursorInfo = Request->Data.SetCursorInfoRequest.Info;
1603 if( Buff == ActiveConsole->ActiveBuffer )
1605 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_CURSOR_INFO, &Buff->CursorInfo, sizeof( Buff->CursorInfo ), 0, 0 );
1606 if( !NT_SUCCESS( Status ) )
1608 DbgPrint( "CSR: Failed to set cursor info\n" );
1609 return Reply->Status = Status;
1613 return Reply->Status = STATUS_SUCCESS;
1616 CSR_API(CsrSetTextAttrib)
1619 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
1620 IO_STATUS_BLOCK Iosb;
1621 PCSRSS_SCREEN_BUFFER Buff;
1623 DPRINT("CsrSetTextAttrib\n");
1625 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1626 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1627 sizeof(LPC_MESSAGE);
1629 Status = CsrGetObject( ProcessData, Request->Data.SetAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1630 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1632 Reply->Status = Status;
1636 Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1637 if( Buff == ActiveConsole->ActiveBuffer )
1639 ScrInfo.wAttributes = Buff->DefaultAttrib;
1640 ScrInfo.dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1641 ScrInfo.dwCursorPosition.Y = ((Buff->CurrentY + Buff->MaxY) - Buff->ShowY) % Buff->MaxY;
1642 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
1643 if( !NT_SUCCESS( Status ) )
1645 DbgPrint( "CSR: Failed to set console info\n" );
1647 return Reply->Status = Status;
1651 return Reply->Status = STATUS_SUCCESS;
1654 CSR_API(CsrSetConsoleMode)
1657 PCSRSS_CONSOLE Console;
1658 PCSRSS_SCREEN_BUFFER Buff;
1660 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1661 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1663 Status = CsrGetObject( ProcessData,
1664 Request->Data.SetConsoleModeRequest.ConsoleHandle,
1665 (Object_t **)&Console );
1666 if( !NT_SUCCESS( Status ) )
1668 Reply->Status = Status;
1673 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1674 if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1675 Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1676 else if( Console->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1677 Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1679 Reply->Status = STATUS_INVALID_HANDLE;
1684 Reply->Status = STATUS_SUCCESS;
1685 return Reply->Status;
1688 CSR_API(CsrGetConsoleMode)
1691 PCSRSS_CONSOLE Console;
1692 PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
1694 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1695 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1697 Status = CsrGetObject( ProcessData,
1698 Request->Data.GetConsoleModeRequest.ConsoleHandle,
1699 (Object_t **)&Console );
1700 if( !NT_SUCCESS( Status ) )
1702 Reply->Status = Status;
1706 Reply->Status = STATUS_SUCCESS;
1707 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1708 if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1709 Reply->Data.GetConsoleModeReply.ConsoleMode = Console->Mode;
1710 else if( Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1711 Reply->Data.GetConsoleModeReply.ConsoleMode = Buff->Mode;
1712 else Status = STATUS_INVALID_HANDLE;
1714 return Reply->Status;
1717 CSR_API(CsrCreateScreenBuffer)
1719 PCSRSS_SCREEN_BUFFER Buff;
1722 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1723 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1725 if (ProcessData == NULL)
1727 return(Reply->Status = STATUS_INVALID_PARAMETER);
1730 Buff = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
1732 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
1734 Status = CsrInitConsoleScreenBuffer( Buff );
1735 if( !NT_SUCCESS( Status ) )
1736 Reply->Status = Status;
1738 Status = CsrInsertObject( ProcessData, &Reply->Data.CreateScreenBufferReply.OutputHandle, &Buff->Header );
1739 if( !NT_SUCCESS( Status ) )
1740 Reply->Status = Status;
1741 else Reply->Status = STATUS_SUCCESS;
1744 return Reply->Status;
1747 CSR_API(CsrSetScreenBuffer)
1750 PCSRSS_SCREEN_BUFFER Buff;
1752 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1753 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1755 Status = CsrGetObject( ProcessData, Request->Data.SetActiveScreenBufferRequest.OutputHandle, (Object_t **)&Buff );
1756 if( !NT_SUCCESS( Status ) )
1757 Reply->Status = Status;
1759 // drop reference to old buffer, maybe delete
1760 if( !InterlockedDecrement( &ProcessData->Console->ActiveBuffer->Header.ReferenceCount ) )
1761 CsrDeleteScreenBuffer( ProcessData->Console->ActiveBuffer );
1762 // tie console to new buffer
1763 ProcessData->Console->ActiveBuffer = Buff;
1764 // inc ref count on new buffer
1765 InterlockedIncrement( &Buff->Header.ReferenceCount );
1766 // if the console is active, redraw it
1767 if( ActiveConsole == ProcessData->Console )
1768 CsrDrawConsole( Buff );
1769 Reply->Status = STATUS_SUCCESS;
1772 return Reply->Status;
1775 CSR_API(CsrSetTitle)
1778 PCSRSS_CONSOLE Console;
1780 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1781 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1783 Status = CsrGetObject( ProcessData, Request->Data.SetTitleRequest.Console, (Object_t **)&Console );
1784 if( !NT_SUCCESS( Status ) )
1785 Reply->Status = Status;
1787 // copy title to console
1788 RtlFreeUnicodeString( &Console->Title );
1789 RtlCreateUnicodeString( &Console->Title, Request->Data.SetTitleRequest.Title );
1790 Reply->Status = STATUS_SUCCESS;
1793 return Reply->Status;
1796 CSR_API(CsrGetTitle)
1799 PCSRSS_CONSOLE Console;
1801 Reply->Header.MessageSize = sizeof (CSRSS_API_REPLY);
1802 Reply->Header.DataSize =
1803 sizeof (CSRSS_API_REPLY)
1804 - sizeof(LPC_MESSAGE);
1806 Status = CsrGetObject (
1808 Request->Data.GetTitleRequest.ConsoleHandle,
1809 (Object_t **) & Console
1811 if ( !NT_SUCCESS( Status ) )
1813 Reply->Status = Status;
1817 HANDLE ConsoleHandle = Request->Data.GetTitleRequest.ConsoleHandle;
1819 /* Copy title of the console to the user title buffer */
1821 & Reply->Data.GetTitleReply,
1822 sizeof (CSRSS_GET_TITLE_REPLY)
1824 Reply->Data.GetTitleReply.ConsoleHandle = ConsoleHandle;
1825 Reply->Data.GetTitleReply.Length = Console->Title.Length;
1826 wcscpy (Reply->Data.GetTitleReply.Title, Console->Title.Buffer);
1827 Reply->Header.MessageSize += Console->Title.Length;
1828 Reply->Header.DataSize += Console->Title.Length;
1829 Reply->Status = STATUS_SUCCESS;
1832 return Reply->Status;
1835 CSR_API(CsrWriteConsoleOutput)
1837 SHORT i, X, Y, SizeX, SizeY;
1838 PCSRSS_SCREEN_BUFFER Buff;
1839 SMALL_RECT ScreenBuffer;
1840 CHAR_INFO* CurCharInfo;
1841 SMALL_RECT WriteRegion;
1842 CHAR_INFO* CharInfo;
1849 DPRINT("CsrWriteConsoleOutput\n");
1851 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1852 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1854 Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputRequest.ConsoleHandle, (Object_t **)&Buff );
1855 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1857 Reply->Status = Status;
1862 BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
1863 PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
1864 BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
1865 CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
1866 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
1867 (((PVOID)CharInfo + PSize) >
1868 (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
1871 Reply->Status = STATUS_ACCESS_VIOLATION;
1872 return(Reply->Status);
1874 WriteRegion = Request->Data.WriteConsoleOutputRequest.WriteRegion;
1876 SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(WriteRegion));
1877 SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(WriteRegion));
1878 WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
1879 WriteRegion.Right = WriteRegion.Left + SizeX - 1;
1881 /* Make sure WriteRegion is inside the screen buffer */
1882 CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1883 if (!CsrpGetIntersection(&WriteRegion, ScreenBuffer, WriteRegion))
1886 /* It is okay to have a WriteRegion completely outside the screen buffer.
1887 No data is written then. */
1888 return (Reply->Status = STATUS_SUCCESS);
1891 for ( i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++ )
1893 CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
1894 Offset = (((Y + Buff->ShowY) % Buff->MaxY) * Buff->MaxX + WriteRegion.Left) * 2;
1895 for ( X = WriteRegion.Left; X <= WriteRegion.Right; X++ )
1897 SET_CELL_BUFFER(Buff, Offset, CurCharInfo->Char.AsciiChar, CurCharInfo->Attributes);
1902 if( Buff == ActiveConsole->ActiveBuffer )
1904 CsrpDrawRegion( ActiveConsole->ActiveBuffer, WriteRegion );
1908 Reply->Data.WriteConsoleOutputReply.WriteRegion.Right = WriteRegion.Left + SizeX - 1;
1909 Reply->Data.WriteConsoleOutputReply.WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
1910 Reply->Data.WriteConsoleOutputReply.WriteRegion.Left = WriteRegion.Left;
1911 Reply->Data.WriteConsoleOutputReply.WriteRegion.Top = WriteRegion.Top;
1912 return (Reply->Status = STATUS_SUCCESS);
1915 CSR_API(CsrFlushInputBuffer)
1917 PLIST_ENTRY CurrentEntry;
1918 PLIST_ENTRY NextEntry;
1919 PCSRSS_CONSOLE Console;
1920 ConsoleInput* Input;
1923 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1924 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1926 Status = CsrGetObject( ProcessData, Request->Data.FlushInputBufferRequest.ConsoleInput, (Object_t **)&Console );
1927 if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1929 Reply->Status = Status;
1934 /* Discard all entries in the input event queue */
1935 while (!IsListEmpty(&Console->InputEvents))
1937 CurrentEntry = RemoveHeadList(&Console->InputEvents);
1938 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1939 /* Destroy the event */
1940 RtlFreeHeap( CsrssApiHeap, 0, Input );
1942 Console->WaitingChars=0;
1945 return (Reply->Status = STATUS_SUCCESS);
1948 CSR_API(CsrScrollConsoleScreenBuffer)
1950 SHORT i, X, Y, SizeX, SizeY;
1951 PCSRSS_SCREEN_BUFFER Buff;
1952 SMALL_RECT ScreenBuffer;
1953 SMALL_RECT SrcRegion;
1954 SMALL_RECT DstRegion;
1955 SMALL_RECT FillRegion;
1956 IO_STATUS_BLOCK Iosb;
1957 CHAR_INFO* CharInfo;
1963 ALIAS(ConsoleHandle,Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle);
1964 ALIAS(ScrollRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle);
1965 ALIAS(UseClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle);
1966 ALIAS(ClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle);
1967 ALIAS(DestinationOrigin,Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin);
1968 ALIAS(Fill,Request->Data.ScrollConsoleScreenBufferRequest.Fill);
1970 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1971 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1973 Status = CsrGetObject( ProcessData, ConsoleHandle, (Object_t **)&Buff );
1974 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1976 Reply->Status = Status;
1981 /* Make sure source rectangle is inside the screen buffer */
1982 CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1983 if (!CsrpGetIntersection(&SrcRegion, ScreenBuffer, ScrollRectangle))
1986 return (Reply->Status = STATUS_INVALID_PARAMETER);
1989 if (UseClipRectangle)
1991 if (!CsrpGetIntersection(&SrcRegion, SrcRegion, ClipRectangle))
1994 return (Reply->Status = STATUS_SUCCESS);
2001 DestinationOrigin.Y,
2002 DestinationOrigin.X,
2003 DestinationOrigin.Y + CsrpRectHeight(ScrollRectangle) - 1,
2004 DestinationOrigin.X + CsrpRectWidth(ScrollRectangle) - 1)
2006 /* Make sure destination rectangle is inside the screen buffer */
2007 if (!CsrpGetIntersection(&DstRegion, DstRegion, ScreenBuffer))
2010 return (Reply->Status = STATUS_INVALID_PARAMETER);
2013 CsrpCopyRegion(Buff, SrcRegion, DstRegion);
2016 /* Get the region that should be filled with the specified character and attributes */
2020 CsrpGetUnion(&FillRegion, SrcRegion, DstRegion);
2022 if (CsrpSubtractRect(&FillRegion, FillRegion, DstRegion))
2024 /* FIXME: The subtracted rectangle is off by one line */
2025 FillRegion.Top += 1;
2027 CsrpFillRegion(Buff, FillRegion, Fill);
2031 if (Buff == ActiveConsole->ActiveBuffer)
2033 /* Draw destination region */
2034 CsrpDrawRegion(ActiveConsole->ActiveBuffer, DstRegion);
2038 /* Draw filled region */
2039 CsrpDrawRegion(ActiveConsole->ActiveBuffer, FillRegion);
2044 return(Reply->Status = STATUS_SUCCESS);
2048 CSR_API(CsrReadConsoleOutputChar)
2051 PCSRSS_SCREEN_BUFFER ScreenBuffer;
2056 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2057 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2058 ReadBuffer = Reply->Data.ReadConsoleOutputCharReply.String;
2062 Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2063 if (!NT_SUCCESS(Status))
2065 Reply->Status = Status;
2067 return(Reply->Status);
2070 if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2072 Reply->Status = STATUS_INVALID_HANDLE;
2074 return(Reply->Status);
2077 Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X + ScreenBuffer->ShowX;
2078 Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
2080 for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
2082 *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX)];
2087 if (Xpos == ScreenBuffer->MaxX)
2092 if (Ypos == ScreenBuffer->MaxY)
2099 Reply->Status = STATUS_SUCCESS;
2100 Reply->Data.ReadConsoleOutputCharReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
2101 Reply->Data.ReadConsoleOutputCharReply.EndCoord.Y = (Ypos - ScreenBuffer->ShowY + ScreenBuffer->MaxY) % ScreenBuffer->MaxY;
2102 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2103 Reply->Header.DataSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2107 return(Reply->Status);
2111 CSR_API(CsrReadConsoleOutputAttrib)
2114 PCSRSS_SCREEN_BUFFER ScreenBuffer;
2119 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2120 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2121 ReadBuffer = Reply->Data.ReadConsoleOutputAttribReply.String;
2125 Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2126 if (!NT_SUCCESS(Status))
2128 Reply->Status = Status;
2130 return(Reply->Status);
2133 if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2135 Reply->Status = STATUS_INVALID_HANDLE;
2137 return(Reply->Status);
2140 Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X + ScreenBuffer->ShowX;
2141 Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
2143 for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2145 *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX) + 1];
2150 if (Xpos == ScreenBuffer->MaxX)
2155 if (Ypos == ScreenBuffer->MaxY)
2162 Reply->Status = STATUS_SUCCESS;
2163 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
2164 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.Y = (Ypos - ScreenBuffer->ShowY + ScreenBuffer->MaxY) % ScreenBuffer->MaxY;
2165 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2166 Reply->Header.DataSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2170 return(Reply->Status);
2174 CSR_API(CsrGetNumberOfConsoleInputEvents)
2177 PCSRSS_CONSOLE Console;
2178 PLIST_ENTRY CurrentItem;
2181 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2182 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2186 Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2187 if (!NT_SUCCESS(Status))
2189 Reply->Status = Status;
2191 return(Reply->Status);
2194 if (Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2196 Reply->Status = STATUS_INVALID_HANDLE;
2198 return(Reply->Status);
2201 CurrentItem = &Console->InputEvents;
2204 // If there are any events ...
2205 if(CurrentItem->Flink != CurrentItem)
2209 CurrentItem = CurrentItem->Flink;
2211 }while(CurrentItem != &Console->InputEvents);
2216 Reply->Status = STATUS_SUCCESS;
2217 Reply->Data.GetNumInputEventsReply.NumInputEvents = NumEvents;
2219 return Reply->Status;
2223 CSR_API(CsrPeekConsoleInput)
2226 PCSRSS_CONSOLE Console;
2229 PLIST_ENTRY CurrentItem;
2230 PLIST_ENTRY NextItem;
2231 PINPUT_RECORD InputRecord;
2235 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2236 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2240 Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2241 if(!NT_SUCCESS(Status))
2243 Reply->Status = Status;
2245 return Reply->Status;
2248 if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2250 Reply->Status = STATUS_INVALID_HANDLE;
2252 return Reply->Status;
2255 InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2256 Length = Request->Data.PeekConsoleInputRequest.Length;
2257 Size = Length * sizeof(INPUT_RECORD);
2259 if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2260 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2263 Reply->Status = STATUS_ACCESS_VIOLATION;
2264 return Reply->Status ;
2269 if(!IsListEmpty(&Console->InputEvents))
2271 CurrentItem = &Console->InputEvents;
2273 while(NumItems < Length)
2276 Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2277 *InputRecord++ = Item->InputEvent;
2279 if(CurrentItem->Flink == &Console->InputEvents)
2282 CurrentItem = CurrentItem->Flink;
2288 Reply->Status = STATUS_SUCCESS;
2289 Reply->Data.PeekConsoleInputReply.Length = NumItems;
2290 return Reply->Status;
2294 CSR_API(CsrReadConsoleOutput)
2296 PCHAR_INFO CharInfo;
2297 PCHAR_INFO CurCharInfo;
2298 PCSRSS_SCREEN_BUFFER ScreenBuffer;
2305 SMALL_RECT ReadRegion;
2306 SMALL_RECT ScreenRect;
2307 DWORD i, Y, X, Offset;
2309 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2310 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2314 Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2315 if(!NT_SUCCESS(Status))
2317 Reply->Status = Status;
2319 return Reply->Status;
2322 if(ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2324 Reply->Status = STATUS_INVALID_HANDLE;
2326 return Reply->Status;
2329 CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
2330 ReadRegion = Request->Data.ReadConsoleOutputRequest.ReadRegion;
2331 BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
2332 BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
2333 Length = BufferSize.X * BufferSize.Y;
2334 Size = Length * sizeof(INPUT_RECORD);
2336 if(((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
2337 || (((PVOID)CharInfo + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2340 Reply->Status = STATUS_ACCESS_VIOLATION;
2341 return Reply->Status ;
2344 SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(ReadRegion));
2345 SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(ReadRegion));
2346 ReadRegion.Bottom = ReadRegion.Top + SizeY;
2347 ReadRegion.Right = ReadRegion.Left + SizeX;
2349 CsrpInitRect(ScreenRect, 0, 0, ScreenBuffer->MaxY - 1, ScreenBuffer->MaxX - 1);
2350 if (!CsrpGetIntersection(&ReadRegion, ScreenRect, ReadRegion))
2353 Reply->Status = STATUS_SUCCESS;
2354 return Reply->Status;
2357 for(i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
2359 CurCharInfo = CharInfo + (i * BufferSize.Y);
2361 Offset = (((Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY) * ScreenBuffer->MaxX + ReadRegion.Left) * 2;
2362 for(X = ReadRegion.Left; X < ReadRegion.Right; ++X)
2364 CurCharInfo->Char.AsciiChar = GET_CELL_BUFFER(ScreenBuffer, Offset);
2365 CurCharInfo->Attributes = GET_CELL_BUFFER(ScreenBuffer, Offset);
2372 Reply->Status = STATUS_SUCCESS;
2373 Reply->Data.ReadConsoleOutputReply.ReadRegion.Right = ReadRegion.Left + SizeX - 1;
2374 Reply->Data.ReadConsoleOutputReply.ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
2375 Reply->Data.ReadConsoleOutputReply.ReadRegion.Left = ReadRegion.Left;
2376 Reply->Data.ReadConsoleOutputReply.ReadRegion.Top = ReadRegion.Top;
2378 return Reply->Status;
2382 CSR_API(CsrWriteConsoleInput)
2384 PINPUT_RECORD InputRecord;
2385 PCSRSS_CONSOLE Console;
2390 PLIST_ENTRY NextItem;
2391 ConsoleInput* Record;
2393 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2394 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2398 Status = CsrGetObject(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, (Object_t**)&Console);
2399 if(!NT_SUCCESS(Status))
2401 Reply->Status = Status;
2403 return Reply->Status;
2406 if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2408 Reply->Status = STATUS_INVALID_HANDLE;
2410 return Reply->Status;
2413 InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
2414 Length = Request->Data.WriteConsoleInputRequest.Length;
2415 Size = Length * sizeof(INPUT_RECORD);
2417 if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2418 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2421 Reply->Status = STATUS_ACCESS_VIOLATION;
2422 return Reply->Status ;
2425 for(i = 0; i < Length; ++i)
2427 Record = RtlAllocateHeap(CsrssApiHeap, 0, sizeof(ConsoleInput));
2431 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
2432 return Reply->Status;
2435 Record->InputEvent = *InputRecord++;
2436 InsertTailList(&Console->InputEvents, &Record->ListEntry);
2441 Reply->Status = STATUS_SUCCESS;
2442 Reply->Data.WriteConsoleInputReply.Length = i;
2443 return Reply->Status;