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) -
49 if( ProcessData->Console )
51 Reply->Status = STATUS_INVALID_PARAMETER;
52 return STATUS_INVALID_PARAMETER;
54 Reply->Status = STATUS_SUCCESS;
55 Console = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_CONSOLE ) );
58 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
59 return STATUS_INSUFFICIENT_RESOURCES;
61 Reply->Status = CsrInitConsole( Console );
62 if( !NT_SUCCESS( Reply->Status ) )
64 RtlFreeHeap( CsrssApiHeap, 0, Console );
67 ProcessData->Console = Console;
68 /* add a reference count because the process is tied to the console */
69 Console->Header.ReferenceCount++;
70 Status = CsrInsertObject( ProcessData, &Reply->Data.AllocConsoleReply.InputHandle, &Console->Header );
71 if( !NT_SUCCESS( Status ) )
73 CsrDeleteConsole( Console );
74 ProcessData->Console = 0;
75 return Reply->Status = Status;
77 Status = CsrInsertObject( ProcessData, &Reply->Data.AllocConsoleReply.OutputHandle, &Console->ActiveBuffer->Header );
78 if( !NT_SUCCESS( Status ) )
80 Console->Header.ReferenceCount--;
81 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
82 ProcessData->Console = 0;
83 return Reply->Status = Status;
85 ClientId.UniqueProcess = (HANDLE)ProcessData->ProcessId;
86 Status = NtOpenProcess( &Process, PROCESS_DUP_HANDLE, 0, &ClientId );
87 if( !NT_SUCCESS( Status ) )
89 DbgPrint( "CSR: NtOpenProcess() failed for handle duplication\n" );
90 Console->Header.ReferenceCount--;
91 ProcessData->Console = 0;
92 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.OutputHandle );
93 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
94 Reply->Status = Status;
97 Status = NtDuplicateObject( NtCurrentProcess(), ProcessData->Console->ActiveEvent, Process, &ProcessData->ConsoleEvent, SYNCHRONIZE, FALSE, 0 );
98 if( !NT_SUCCESS( Status ) )
100 DbgPrint( "CSR: NtDuplicateObject() failed: %x\n", Status );
102 Console->Header.ReferenceCount--;
103 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.OutputHandle );
104 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
105 ProcessData->Console = 0;
106 Reply->Status = Status;
110 return STATUS_SUCCESS;
113 CSR_API(CsrFreeConsole)
115 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
116 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
119 Reply->Status = STATUS_NOT_IMPLEMENTED;
121 return(STATUS_NOT_IMPLEMENTED);
124 CSR_API(CsrReadConsole)
126 PLIST_ENTRY CurrentEntry;
130 ULONG nNumberOfCharsToRead;
131 PCSRSS_CONSOLE Console;
134 /* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
135 nNumberOfCharsToRead = Request->Data.ReadConsoleRequest.NrCharactersToRead > CSRSS_MAX_READ_CONSOLE_REQUEST ? CSRSS_MAX_READ_CONSOLE_REQUEST : Request->Data.ReadConsoleRequest.NrCharactersToRead;
136 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
137 Reply->Header.DataSize = Reply->Header.MessageSize -
139 Buffer = Reply->Data.ReadConsoleReply.Buffer;
140 Reply->Data.ReadConsoleReply.EventHandle = ProcessData->ConsoleEvent;
142 Status = CsrGetObject( ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle, (Object_t **)&Console );
143 if( !NT_SUCCESS( Status ) )
145 Reply->Status = Status;
149 if( Console->Header.Type != CSRSS_CONSOLE_MAGIC )
151 Reply->Status = STATUS_INVALID_HANDLE;
153 return STATUS_INVALID_HANDLE;
155 for (; i<nNumberOfCharsToRead && Console->InputEvents.Flink != &Console->InputEvents; i++ )
157 // remove input event from queue
158 CurrentEntry = RemoveHeadList(&Console->InputEvents);
159 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
161 // only pay attention to valid ascii chars, on key down
162 if( Input->InputEvent.EventType == KEY_EVENT &&
163 Input->InputEvent.Event.KeyEvent.bKeyDown == TRUE &&
164 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar )
166 // backspace handling
167 if( Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' )
169 // echo if it has not already been done, and either we or the client has chars to be deleted
170 if( !Input->Echoed && ( i || Request->Data.ReadConsoleRequest.nCharsCanBeDeleted ) )
171 CsrpWriteConsole( Console->ActiveBuffer, &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
173 i-=2; // if we already have something to return, just back it up by 2
175 { // otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer
176 Reply->Data.ReadConsoleReply.NrCharactersRead = 0;
177 Reply->Status = STATUS_NOTIFY_CLEANUP;
178 Console->WaitingChars--;
179 RtlFreeHeap( CsrssApiHeap, 0, Input );
181 return STATUS_NOTIFY_CLEANUP;
183 Request->Data.ReadConsoleRequest.nCharsCanBeDeleted--;
184 Input->Echoed = TRUE; // mark as echoed so we don't echo it below
186 // do not copy backspace to buffer
187 else Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar;
188 // echo to screen if enabled and we did not already echo the char
189 if( Console->Mode & ENABLE_ECHO_INPUT &&
191 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
192 CsrpWriteConsole( Console->ActiveBuffer, &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
195 Console->WaitingChars--;
196 RtlFreeHeap( CsrssApiHeap, 0, Input );
198 Reply->Data.ReadConsoleReply.NrCharactersRead = i;
200 Reply->Status = STATUS_PENDING; // we didn't read anything
201 else if( Console->Mode & ENABLE_LINE_INPUT )
202 if( !Console->WaitingLines || Buffer[i-1] != '\n' )
204 Reply->Status = STATUS_PENDING; // line buffered, didn't get a complete line
207 Console->WaitingLines--;
208 Reply->Status = STATUS_SUCCESS; // line buffered, did get a complete line
210 else Reply->Status = STATUS_SUCCESS; // not line buffered, did read something
211 if( Reply->Status == STATUS_PENDING )
213 Console->EchoCount = nNumberOfCharsToRead - i;
216 Console->EchoCount = 0; // if the client is no longer waiting on input, do not echo
218 Reply->Header.MessageSize += i;
220 return Reply->Status;
223 #define GET_CELL_BUFFER(b,o)\
226 #define SET_CELL_BUFFER(b,o,c,a)\
227 (b)->Buffer[(o)++]=(c);\
228 (b)->Buffer[(o)++]=(a);
232 PCSRSS_SCREEN_BUFFER Buff,
236 DWORD Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + StartX);
238 for ( ; StartX < Buff->MaxX; StartX ++ )
240 /* Fill the cell: Offset is incremented by the macro */
241 SET_CELL_BUFFER(Buff,Offset,' ',Buff->DefaultAttrib)
245 NTSTATUS STDCALL CsrpWriteConsole( PCSRSS_SCREEN_BUFFER Buff, CHAR *Buffer, DWORD Length, BOOL Attrib )
247 IO_STATUS_BLOCK Iosb;
252 for( i = 0; i < Length; i++ )
254 switch( Buffer[ i ] )
259 /* slide the viewable screen */
260 if( ((PhysicalConsoleSize.Y + Buff->ShowY) % Buff->MaxY) == (Buff->CurrentY + 1) % Buff->MaxY)
261 if( ++Buff->ShowY == (Buff->MaxY - 1) )
263 if( ++Buff->CurrentY == Buff->MaxY )
267 ClearLineBuffer (Buff, 0);
271 if( Buff->CurrentX == 0 )
273 /* slide viewable screen up */
274 if( Buff->ShowY == Buff->CurrentY )
276 if( Buff->ShowY == 0 )
277 Buff->ShowY = Buff->MaxY;
281 /* slide virtual position up */
282 Buff->CurrentX = Buff->MaxX;
283 if( Buff->CurrentY == 0 )
284 Buff->CurrentY = Buff->MaxY;
290 Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + Buff->CurrentX);
291 SET_CELL_BUFFER(Buff,Offset,' ',Buff->DefaultAttrib);
299 CsrpWriteConsole(Buff, " ", (8 - (Buff->CurrentX % 8)), FALSE);
303 Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
304 Buff->Buffer[Offset ++] = Buffer[ i ];
306 Buff->Buffer[Offset] = Buff->DefaultAttrib;
308 if( Buff->CurrentX == Buff->MaxX )
310 /* if end of line, go to next */
312 if( ++Buff->CurrentY == Buff->MaxY )
314 /* if end of buffer, wrap back to beginning */
318 ClearLineBuffer (Buff, 0);
319 /* slide the viewable screen */
320 if( (Buff->CurrentY - Buff->ShowY) == PhysicalConsoleSize.Y )
321 if( ++Buff->ShowY == Buff->MaxY )
326 if( Buff == ActiveConsole->ActiveBuffer )
327 { /* only write to screen if Console is Active, and not scrolled up */
330 Status = NtWriteFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, Buffer, Length, NULL, 0);
331 if (!NT_SUCCESS(Status))
332 DbgPrint("CSR: Write failed\n");
335 return(STATUS_SUCCESS);
338 #define CsrpInitRect(_Rect, _Top, _Left, _Bottom, _Right) \
340 ((_Rect).Top) = _Top; \
341 ((_Rect).Left) = _Left; \
342 ((_Rect).Bottom) = _Bottom; \
343 ((_Rect).Right) = _Right; \
346 #define CsrpRectHeight(Rect) \
347 ((Rect.Bottom) - (Rect.Top) + 1)
349 #define CsrpRectWidth(Rect) \
350 ((Rect.Right) - (Rect.Left) + 1)
352 #define CsrpIsRectEmpty(Rect) \
353 ((Rect.Left >= Rect.Right) || (Rect.Top >= Rect.Bottom))
356 inline BOOLEAN CsrpIsEqualRect(
360 return ((Rect1.Left == Rect2.Left) && (Rect1.Right == Rect2.Right) &&
361 (Rect1.Top == Rect2.Top) && (Rect1.Bottom == Rect2.Bottom));
364 inline BOOLEAN CsrpGetIntersection(
365 PSMALL_RECT Intersection,
369 if (CsrpIsRectEmpty(Rect1) ||
370 (CsrpIsRectEmpty(Rect2)) ||
371 (Rect1.Top >= Rect2.Bottom) ||
372 (Rect1.Left >= Rect2.Right) ||
373 (Rect1.Bottom <= Rect2.Top) ||
374 (Rect1.Right <= Rect2.Left))
376 /* The rectangles do not intersect */
377 CsrpInitRect(*Intersection, 0, 0, 0, 0)
383 RtlMax(Rect1.Top, Rect2.Top),
384 RtlMax(Rect1.Left, Rect2.Left),
385 RtlMin(Rect1.Bottom, Rect2.Bottom),
386 RtlMin(Rect1.Right, Rect2.Right));
390 inline BOOLEAN CsrpGetUnion(
395 if (CsrpIsRectEmpty(Rect1))
397 if (CsrpIsRectEmpty(Rect2))
399 CsrpInitRect(*Union, 0, 0, 0, 0);
407 if (CsrpIsRectEmpty(Rect2))
415 RtlMin(Rect1.Top, Rect2.Top),
416 RtlMin(Rect1.Left, Rect2.Left),
417 RtlMax(Rect1.Bottom, Rect2.Bottom),
418 RtlMax(Rect1.Right, Rect2.Right));
424 inline BOOLEAN CsrpSubtractRect(
425 PSMALL_RECT Subtraction,
431 if (CsrpIsRectEmpty(Rect1))
433 CsrpInitRect(*Subtraction, 0, 0, 0, 0);
436 *Subtraction = Rect1;
437 if (CsrpGetIntersection(&tmp, Rect1, Rect2))
439 if (CsrpIsEqualRect(tmp, *Subtraction))
441 CsrpInitRect(*Subtraction, 0, 0, 0, 0);
444 if ((tmp.Top == Subtraction->Top) && (tmp.Bottom == Subtraction->Bottom))
446 if (tmp.Left == Subtraction->Left)
447 Subtraction->Left = tmp.Right;
448 else if (tmp.Right == Subtraction->Right)
449 Subtraction->Right = tmp.Left;
451 else if ((tmp.Left == Subtraction->Left) && (tmp.Right == Subtraction->Right))
453 if (tmp.Top == Subtraction->Top)
454 Subtraction->Top = tmp.Bottom;
455 else if (tmp.Bottom == Subtraction->Bottom)
456 Subtraction->Bottom = tmp.Top;
463 * Screen buffer must be locked when this function is called
465 static VOID CsrpCopyRegion(
466 PCSRSS_SCREEN_BUFFER ScreenBuffer,
467 SMALL_RECT SrcRegion,
468 SMALL_RECT DstRegion)
475 DstY = DstRegion.Top;
476 BytesPerLine = CsrpRectWidth(DstRegion) * 2;
477 for (SrcY = SrcRegion.Top; SrcY <= SrcRegion.Bottom; SrcY++)
479 SrcOffset = (SrcY * ScreenBuffer->MaxX * 2) + (SrcRegion.Left * 2);
480 DstOffset = (DstY * ScreenBuffer->MaxX * 2) + (DstRegion.Left * 2);
482 &ScreenBuffer->Buffer[DstOffset],
483 &ScreenBuffer->Buffer[SrcOffset],
490 * Screen buffer must be locked when this function is called
492 static VOID CsrpFillRegion(
493 PCSRSS_SCREEN_BUFFER ScreenBuffer,
500 for (Y = Region.Top; Y <= Region.Bottom; Y++)
502 Offset = (Y * ScreenBuffer->MaxX + Region.Left) * 2;
503 for (X = Region.Left; X <= Region.Right; X++)
505 SET_CELL_BUFFER(ScreenBuffer, Offset, CharInfo.Char.AsciiChar, CharInfo.Attributes);
511 * Screen buffer must be locked when this function is called
513 inline NTSTATUS CsrpSetConsoleDeviceCursor(PCSRSS_SCREEN_BUFFER ScreenBuffer, SHORT X, SHORT Y)
515 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
516 IO_STATUS_BLOCK Iosb;
518 ScrInfo.dwCursorPosition.X = X;
519 ScrInfo.dwCursorPosition.Y = Y;
520 ScrInfo.wAttributes = ScreenBuffer->DefaultAttrib;
522 return NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
523 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
527 * Region - Region of virtual screen buffer to draw onto the physical console
528 * Screen buffer must be locked when this function is called
530 static VOID CsrpDrawRegion(
531 PCSRSS_SCREEN_BUFFER ScreenBuffer,
534 IO_STATUS_BLOCK Iosb;
536 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
543 Mode.dwMode = 0; /* clear ENABLE_PROCESSED_OUTPUT mode */
544 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
545 IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
546 if( !NT_SUCCESS( Status ) )
548 DbgPrint( "CSR: Failed to set console mode\n" );
552 /* blast out buffer */
553 BytesPerLine = CsrpRectWidth(Region) * 2;
554 SrcOffset = (Region.Top * ScreenBuffer->MaxX + Region.Left) * 2;
555 SrcDelta = ScreenBuffer->MaxX * 2;
556 for( i = Region.Top - ScreenBuffer->ShowY, y = ScreenBuffer->ShowY;
557 i <= Region.Bottom - ScreenBuffer->ShowY; i++ )
559 /* Position the cursor correctly */
560 Status = CsrpSetConsoleDeviceCursor(ScreenBuffer, Region.Left - ScreenBuffer->ShowX, i);
561 if( !NT_SUCCESS( Status ) )
563 DbgPrint( "CSR: Failed to set console info\n" );
567 Status = NtWriteFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
568 &ScreenBuffer->Buffer[ SrcOffset ],
569 BytesPerLine, 0, 0 );
570 if( !NT_SUCCESS( Status ) )
572 DbgPrint( "CSR: Write to console failed\n" );
576 /* wrap back around the end of the buffer */
577 if( ++y == ScreenBuffer->MaxY )
580 SrcOffset = Region.Left * 2;
584 SrcOffset += SrcDelta;
587 Mode.dwMode = ENABLE_PROCESSED_OUTPUT;
588 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
589 IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
590 if( !NT_SUCCESS( Status ) )
592 DbgPrint( "CSR: Failed to set console mode\n" );
595 Status = CsrpSetConsoleDeviceCursor(
597 ScreenBuffer->CurrentX - ScreenBuffer->ShowX,
598 ((ScreenBuffer->CurrentY + ScreenBuffer->MaxY) - ScreenBuffer->ShowY) % ScreenBuffer->MaxY);
599 if( !NT_SUCCESS( Status ) )
601 DbgPrint( "CSR: Failed to set console info\n" );
604 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
605 IOCTL_CONSOLE_SET_CURSOR_INFO, &ScreenBuffer->CursorInfo,
606 sizeof( ScreenBuffer->CursorInfo ), 0, 0 );
607 if( !NT_SUCCESS( Status ) )
609 DbgPrint( "CSR: Failed to set cursor info\n" );
615 CSR_API(CsrWriteConsole)
617 BYTE *Buffer = Request->Data.WriteConsoleRequest.Buffer;
618 PCSRSS_SCREEN_BUFFER Buff;
620 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
621 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
625 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle,
626 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
629 return Reply->Status = STATUS_INVALID_HANDLE;
631 CsrpWriteConsole( Buff, Buffer, Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE );
633 return Reply->Status = STATUS_SUCCESS;
637 NTSTATUS STDCALL CsrInitConsoleScreenBuffer( PCSRSS_SCREEN_BUFFER Console )
639 Console->Header.Type = CSRSS_SCREEN_BUFFER_MAGIC;
640 Console->Header.ReferenceCount = 0;
641 Console->MaxX = PhysicalConsoleSize.X;
642 Console->MaxY = PhysicalConsoleSize.Y;
645 Console->CurrentX = 0;
646 Console->CurrentY = 0;
647 Console->Buffer = RtlAllocateHeap( CsrssApiHeap, 0, Console->MaxX * Console->MaxY * 2 );
648 if( Console->Buffer == 0 )
649 return STATUS_INSUFFICIENT_RESOURCES;
650 Console->DefaultAttrib = 0x17;
651 /* initialize buffer to be empty with default attributes */
652 for( ; Console->CurrentY < Console->MaxY; Console->CurrentY++ )
654 ClearLineBuffer (Console, 0);
656 Console->CursorInfo.bVisible = TRUE;
657 Console->CursorInfo.dwSize = 5;
658 Console->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
659 Console->CurrentX = 0;
660 Console->CurrentY = 0;
661 return STATUS_SUCCESS;
664 VOID STDCALL CsrDeleteScreenBuffer( PCSRSS_SCREEN_BUFFER Buffer )
666 RtlFreeHeap( CsrssApiHeap, 0, Buffer->Buffer );
667 RtlFreeHeap( CsrssApiHeap, 0, Buffer );
670 NTSTATUS STDCALL CsrInitConsole(PCSRSS_CONSOLE Console)
673 OBJECT_ATTRIBUTES ObjectAttributes;
675 Console->Title.MaximumLength = Console->Title.Length = 0;
676 Console->Title.Buffer = 0;
678 RtlCreateUnicodeString( &Console->Title, L"Command Prompt" );
680 Console->Header.ReferenceCount = 0;
681 Console->WaitingChars = 0;
682 Console->WaitingLines = 0;
683 Console->EchoCount = 0;
684 Console->Header.Type = CSRSS_CONSOLE_MAGIC;
685 Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
686 Console->EarlyReturn = FALSE;
687 InitializeListHead(&Console->InputEvents);
689 InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_INHERIT, NULL, NULL);
691 Status = NtCreateEvent( &Console->ActiveEvent, STANDARD_RIGHTS_ALL, &ObjectAttributes, FALSE, FALSE );
692 if( !NT_SUCCESS( Status ) )
696 Console->ActiveBuffer = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
697 if( !Console->ActiveBuffer )
699 NtClose( Console->ActiveEvent );
700 return STATUS_INSUFFICIENT_RESOURCES;
702 Status = CsrInitConsoleScreenBuffer( Console->ActiveBuffer );
703 if( !NT_SUCCESS( Status ) )
705 NtClose( Console->ActiveEvent );
706 RtlFreeHeap( CsrssApiHeap, 0, Console->ActiveBuffer );
709 /* add a reference count because the buffer is tied to the console */
710 Console->ActiveBuffer->Header.ReferenceCount++;
711 /* make console active, and insert into console list */
715 Console->Prev = ActiveConsole;
716 Console->Next = ActiveConsole->Next;
717 ActiveConsole->Next->Prev = Console;
718 ActiveConsole->Next = Console;
721 Console->Prev = Console;
722 Console->Next = Console;
724 ActiveConsole = Console;
725 /* copy buffer contents to screen */
726 CsrDrawConsole( Console->ActiveBuffer );
728 return STATUS_SUCCESS;
731 /***************************************************************
732 * CsrDrawConsole blasts the console buffer onto the screen *
733 * must be called while holding the active console lock *
734 **************************************************************/
735 VOID STDCALL CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff )
743 Buff->ShowY + PhysicalConsoleSize.Y - 1,
744 Buff->ShowX + PhysicalConsoleSize.X - 1);
746 CsrpDrawRegion(Buff, Region);
750 VOID STDCALL CsrDeleteConsole( PCSRSS_CONSOLE Console )
753 DPRINT( "CsrDeleteConsole\n" );
755 /* Drain input event queue */
756 while( Console->InputEvents.Flink != &Console->InputEvents )
758 Event = (ConsoleInput *)Console->InputEvents.Flink;
759 Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
760 Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
761 RtlFreeHeap( CsrssApiHeap, 0, Event );
763 /* Switch to next console */
764 if( ActiveConsole == Console )
766 if( Console->Next != Console )
768 ActiveConsole = Console->Next;
769 Console->Prev->Next = Console->Next;
770 Console->Next->Prev = Console->Prev;
772 else ActiveConsole = 0;
775 CsrDrawConsole( ActiveConsole->ActiveBuffer );
777 if( !--Console->ActiveBuffer->Header.ReferenceCount )
778 CsrDeleteScreenBuffer( Console->ActiveBuffer );
779 NtClose( Console->ActiveEvent );
780 RtlFreeUnicodeString( &Console->Title );
781 RtlFreeHeap( CsrssApiHeap, 0, Console );
784 VOID STDCALL CsrInitConsoleSupport(VOID)
786 OBJECT_ATTRIBUTES ObjectAttributes;
787 UNICODE_STRING DeviceName;
789 IO_STATUS_BLOCK Iosb;
790 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
792 DPRINT("CSR: CsrInitConsoleSupport()\n");
794 RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\BlueScreen");
795 InitializeObjectAttributes(&ObjectAttributes,
800 Status = NtOpenFile(&ConsoleDeviceHandle,
805 FILE_SYNCHRONOUS_IO_ALERT);
806 if (!NT_SUCCESS(Status))
808 DbgPrint("CSR: Failed to open console. Expect problems.\n");
811 RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\Keyboard");
812 InitializeObjectAttributes(&ObjectAttributes,
817 Status = NtOpenFile(&KeyboardDeviceHandle,
823 if (!NT_SUCCESS(Status))
825 DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
829 RtlInitializeCriticalSection( &ActiveConsoleLock );
830 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, &ScrInfo, sizeof( ScrInfo ) );
831 if( !NT_SUCCESS( Status ) )
833 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
836 PhysicalConsoleSize = ScrInfo.dwSize;
839 VOID Console_Api( DWORD RefreshEvent )
841 /* keep reading events from the keyboard and stuffing them into the current
842 console's input queue */
843 ConsoleInput *KeyEventRecord;
844 ConsoleInput *TempInput;
845 IO_STATUS_BLOCK Iosb;
847 HANDLE Events[2]; // 0 = keyboard, 1 = refresh
850 PCSRSS_CONSOLE SwapConsole = 0; // console we are thinking about swapping with
853 Status = NtCreateEvent( &Events[0], STANDARD_RIGHTS_ALL, NULL, FALSE, FALSE );
854 if( !NT_SUCCESS( Status ) )
856 DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status );
857 NtTerminateProcess( NtCurrentProcess(), Status );
859 Events[1] = (HANDLE)RefreshEvent;
862 KeyEventRecord = RtlAllocateHeap(CsrssApiHeap,
864 sizeof(ConsoleInput));
865 if ( KeyEventRecord == 0 )
867 DbgPrint( "CSR: Memory allocation failure!" );
870 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
871 Status = NtReadFile( KeyboardDeviceHandle, Events[0], NULL, NULL, &Iosb,
872 &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 );
873 if( !NT_SUCCESS( Status ) )
875 DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
876 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
879 if( Status == STATUS_PENDING )
883 Status = NtWaitForMultipleObjects( 2, Events, WaitAny, FALSE, NULL );
884 if( Status == STATUS_WAIT_0 + 1 )
887 CsrDrawConsole( ActiveConsole->ActiveBuffer );
891 else if( Status != STATUS_WAIT_0 )
893 DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status );
894 NtTerminateProcess( NtCurrentProcess(), Status );
899 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
900 ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED )&&
901 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_TAB )
902 if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
907 unsigned int src, dst;
909 /* alt-tab, swap consoles */
910 // move SwapConsole to next console, and print its title
913 SwapConsole = ActiveConsole;
915 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED )
916 SwapConsole = SwapConsole->Prev;
917 else SwapConsole = SwapConsole->Next;
918 Title.MaximumLength = RtlUnicodeStringToAnsiSize( &SwapConsole->Title );
920 Buffer = RtlAllocateHeap( CsrssApiHeap,
922 sizeof( COORD ) + Title.MaximumLength );
923 pos = (COORD *)Buffer;
924 Title.Buffer = Buffer + sizeof( COORD );
926 /* this does not seem to work
927 RtlUnicodeStringToAnsiString( &Title, &SwapConsole->Title, FALSE ); */
929 for( src = 0, dst = 0; src < SwapConsole->Title.Length; src++, dst++ )
930 Title.Buffer[dst] = (char)SwapConsole->Title.Buffer[dst];
932 pos->Y = PhysicalConsoleSize.Y / 2;
933 pos->X = ( PhysicalConsoleSize.X - Title.MaximumLength ) / 2;
934 // redraw the console to clear off old title
935 CsrDrawConsole( ActiveConsole->ActiveBuffer );
936 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
941 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
945 sizeof (COORD) + Title.MaximumLength );
946 if( !NT_SUCCESS( Status ) )
948 DPRINT1( "Error writing to console\n" );
950 RtlFreeHeap( CsrssApiHeap, 0, Buffer );
953 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
957 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
960 else if( SwapConsole &&
961 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_MENU &&
962 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == FALSE )
964 // alt key released, swap consoles
968 if( SwapConsole != ActiveConsole )
970 // first remove swapconsole from the list
971 SwapConsole->Prev->Next = SwapConsole->Next;
972 SwapConsole->Next->Prev = SwapConsole->Prev;
973 // now insert before activeconsole
974 SwapConsole->Next = ActiveConsole;
975 SwapConsole->Prev = ActiveConsole->Prev;
976 ActiveConsole->Prev->Next = SwapConsole;
977 ActiveConsole->Prev = SwapConsole;
979 ActiveConsole = SwapConsole;
981 CsrDrawConsole( ActiveConsole->ActiveBuffer );
985 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
986 ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) &&
987 ( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP ||
988 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) )
990 if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
992 /* scroll up or down */
994 if( ActiveConsole == 0 )
996 DbgPrint( "CSR: No Active Console!\n" );
998 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1001 if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP )
1003 /* only scroll up if there is room to scroll up into */
1004 if( ActiveConsole->ActiveBuffer->ShowY != ((ActiveConsole->ActiveBuffer->CurrentY + 1) %
1005 ActiveConsole->ActiveBuffer->MaxY) )
1006 ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY +
1007 ActiveConsole->ActiveBuffer->MaxY - 1) % ActiveConsole->ActiveBuffer->MaxY;
1009 else if( ActiveConsole->ActiveBuffer->ShowY != ActiveConsole->ActiveBuffer->CurrentY )
1010 /* only scroll down if there is room to scroll down into */
1011 if( ActiveConsole->ActiveBuffer->ShowY % ActiveConsole->ActiveBuffer->MaxY !=
1012 ActiveConsole->ActiveBuffer->CurrentY )
1014 if( ((ActiveConsole->ActiveBuffer->CurrentY + 1) % ActiveConsole->ActiveBuffer->MaxY) !=
1015 (ActiveConsole->ActiveBuffer->ShowY + PhysicalConsoleSize.Y) % ActiveConsole->ActiveBuffer->MaxY )
1016 ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY + 1) %
1017 ActiveConsole->ActiveBuffer->MaxY;
1018 CsrDrawConsole( ActiveConsole->ActiveBuffer );
1021 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1025 if( ActiveConsole == 0 )
1027 DbgPrint( "CSR: No Active Console!\n" );
1029 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1032 // process special keys if enabled
1033 if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) )
1034 switch( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar )
1037 // add a \n to the queue as well
1039 updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
1040 KeyEventRecord->Echoed = FALSE;
1041 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
1042 InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1043 ActiveConsole->WaitingChars++;
1044 KeyEventRecord = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( ConsoleInput ) );
1045 if( !KeyEventRecord )
1047 DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
1051 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1052 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
1053 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
1054 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
1055 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
1057 // add event to the queue
1058 InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1059 // if line input mode is enabled, only wake the client on enter key down
1060 if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT ) ||
1061 ActiveConsole->EarlyReturn ||
1062 ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' &&
1063 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) )
1065 NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1066 if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1067 ActiveConsole->WaitingLines++;
1069 KeyEventRecord->Echoed = FALSE;
1070 if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) &&
1071 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' &&
1072 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown )
1074 // walk the input queue looking for a char to backspace
1075 for( TempInput = (ConsoleInput *)ActiveConsole->InputEvents.Blink;
1076 TempInput != (ConsoleInput *)&ActiveConsole->InputEvents &&
1077 (TempInput->InputEvent.EventType != KEY_EVENT ||
1078 TempInput->InputEvent.Event.KeyEvent.bKeyDown == FALSE ||
1079 TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' );
1080 TempInput = (ConsoleInput *)TempInput->ListEntry.Blink );
1081 // if we found one, delete it, otherwise, wake the client
1082 if( TempInput != (ConsoleInput *)&ActiveConsole->InputEvents )
1084 // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
1085 RemoveEntryList(&TempInput->ListEntry);
1086 if( TempInput->Echoed )
1087 CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1088 RtlFreeHeap( CsrssApiHeap, 0, TempInput );
1089 RemoveEntryList(&KeyEventRecord->ListEntry);
1090 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1091 ActiveConsole->WaitingChars -= 2;
1093 else NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1096 // echo chars if we are supposed to and client is waiting for some
1097 if( ( ActiveConsole->Mode & ENABLE_ECHO_INPUT ) && ActiveConsole->EchoCount &&
1098 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar &&
1099 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE &&
1100 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
1102 // mark the char as already echoed
1103 CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1104 ActiveConsole->EchoCount--;
1105 KeyEventRecord->Echoed = TRUE;
1108 ActiveConsole->WaitingChars++;
1109 if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT) )
1110 NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1115 CSR_API(CsrGetScreenBufferInfo)
1118 PCSRSS_SCREEN_BUFFER Buff;
1119 PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1120 IO_STATUS_BLOCK Iosb;
1122 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1123 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1124 sizeof(LPC_MESSAGE);
1127 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle,
1128 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1131 return Reply->Status = STATUS_INVALID_HANDLE;
1133 pInfo = &Reply->Data.ScreenBufferInfoReply.Info;
1134 if( Buff == ActiveConsole->ActiveBuffer )
1136 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1137 IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, pInfo, sizeof( *pInfo ) );
1138 if( !NT_SUCCESS( Status ) )
1139 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
1140 Reply->Status = Status;
1143 pInfo->dwSize.X = PhysicalConsoleSize.X;
1144 pInfo->dwSize.Y = PhysicalConsoleSize.Y;
1145 pInfo->dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1146 pInfo->dwCursorPosition.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1147 pInfo->wAttributes = Buff->DefaultAttrib;
1148 pInfo->srWindow.Left = 0;
1149 pInfo->srWindow.Right = PhysicalConsoleSize.X - 1;
1150 pInfo->srWindow.Top = 0;
1151 pInfo->srWindow.Bottom = PhysicalConsoleSize.Y - 1;
1152 Reply->Status = STATUS_SUCCESS;
1155 return Reply->Status;
1158 CSR_API(CsrSetCursor)
1161 PCSRSS_SCREEN_BUFFER Buff;
1162 CONSOLE_SCREEN_BUFFER_INFO Info;
1163 IO_STATUS_BLOCK Iosb;
1165 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1166 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1167 sizeof(LPC_MESSAGE);
1170 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.SetCursorRequest.ConsoleHandle,
1171 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1174 return Reply->Status = STATUS_INVALID_HANDLE;
1176 Info.dwCursorPosition = Request->Data.SetCursorRequest.Position;
1177 Info.wAttributes = Buff->DefaultAttrib;
1178 if( Buff == ActiveConsole->ActiveBuffer )
1180 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1181 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &Info, sizeof( Info ), 0, 0 );
1182 if( !NT_SUCCESS( Status ) )
1183 DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
1186 Buff->CurrentX = Info.dwCursorPosition.X + Buff->ShowX;
1187 Buff->CurrentY = (Info.dwCursorPosition.Y + Buff->ShowY) % Buff->MaxY;
1189 return Reply->Status = Status;
1192 CSR_API(CsrWriteConsoleOutputChar)
1194 BYTE *Buffer = Request->Data.WriteConsoleOutputCharRequest.String;
1195 PCSRSS_SCREEN_BUFFER Buff;
1198 IO_STATUS_BLOCK Iosb;
1200 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1201 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1202 sizeof(LPC_MESSAGE);
1204 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1207 return Reply->Status = STATUS_INVALID_HANDLE;
1211 Buff->CurrentX = Request->Data.WriteConsoleOutputCharRequest.Coord.X;
1212 Buff->CurrentY = Request->Data.WriteConsoleOutputCharRequest.Coord.Y;
1213 Buffer[Request->Data.WriteConsoleOutputCharRequest.Length] = 0;
1214 CsrpWriteConsole( Buff, Buffer, Request->Data.WriteConsoleOutputCharRequest.Length, FALSE );
1215 if( ActiveConsole->ActiveBuffer == Buff )
1217 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1222 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
1225 &Request->Data.WriteConsoleOutputCharRequest.Coord,
1226 sizeof (COORD) + Request->Data.WriteConsoleOutputCharRequest.Length );
1227 if( !NT_SUCCESS( Status ) )
1228 DPRINT1( "Failed to write output chars: %x\n", Status );
1230 Reply->Data.WriteConsoleOutputCharReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1231 Reply->Data.WriteConsoleOutputCharReply.EndCoord.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1235 return Reply->Status = STATUS_SUCCESS;
1238 CSR_API(CsrFillOutputChar)
1240 PCSRSS_SCREEN_BUFFER Buff;
1243 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1244 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1245 sizeof(LPC_MESSAGE);
1248 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1251 return Reply->Status = STATUS_INVALID_HANDLE;
1253 X = Request->Data.FillOutputRequest.Position.X + Buff->ShowX;
1254 Y = Request->Data.FillOutputRequest.Position.Y + Buff->ShowY;
1255 for( i = 0; i < Request->Data.FillOutputRequest.Length; i++ )
1257 Buff->Buffer[ (Y * 2 * Buff->MaxX) + (X * 2) ] = Request->Data.FillOutputRequest.Char;
1258 if( ++X == Buff->MaxX )
1260 if( ++Y == Buff->MaxY )
1265 if( Buff == ActiveConsole->ActiveBuffer )
1266 CsrDrawConsole( Buff );
1268 return Reply->Status;
1271 CSR_API(CsrReadInputEvent)
1273 PLIST_ENTRY CurrentEntry;
1274 PCSRSS_CONSOLE Console;
1276 ConsoleInput *Input;
1278 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1279 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1280 sizeof(LPC_MESSAGE);
1281 Reply->Data.ReadInputReply.Event = ProcessData->ConsoleEvent;
1284 Status = CsrGetObject( ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, (Object_t **)&Console );
1285 if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? 0 : STATUS_INVALID_HANDLE))
1287 Reply->Status = Status;
1292 // only get input if there is any
1293 if( Console->InputEvents.Flink != &Console->InputEvents )
1295 CurrentEntry = RemoveHeadList(&Console->InputEvents);
1296 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1297 Reply->Data.ReadInputReply.Input = Input->InputEvent;
1299 if( Input->InputEvent.EventType == KEY_EVENT )
1301 if( Console->Mode & ENABLE_LINE_INPUT &&
1302 Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE &&
1303 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1304 Console->WaitingLines--;
1305 Console->WaitingChars--;
1307 RtlFreeHeap( CsrssApiHeap, 0, Input );
1308 Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents) ? TRUE : FALSE;
1309 Status = STATUS_SUCCESS;
1310 Console->EarlyReturn = FALSE; // clear early return
1313 Status = STATUS_PENDING;
1314 Console->EarlyReturn = TRUE; // mark for early return
1317 return Reply->Status = Status;
1320 CSR_API(CsrWriteConsoleOutputAttrib)
1323 PCSRSS_SCREEN_BUFFER Buff;
1326 IO_STATUS_BLOCK Iosb;
1328 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1329 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1330 sizeof(LPC_MESSAGE);
1332 Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1333 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1335 Reply->Status = Status;
1341 Buff->CurrentX = Request->Data.WriteConsoleOutputAttribRequest.Coord.X + Buff->ShowX;
1342 Buff->CurrentY = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1343 for( c = 0; c < Request->Data.WriteConsoleOutputAttribRequest.Length; c++ )
1345 Buff->Buffer[(Buff->CurrentY * Buff->MaxX * 2) + (Buff->CurrentX * 2) + 1] = Request->Data.WriteConsoleOutputAttribRequest.String[c];
1346 if( ++Buff->CurrentX == Buff->MaxX )
1349 if( ++Buff->CurrentY == Buff->MaxY )
1353 if( Buff == ActiveConsole->ActiveBuffer )
1355 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1360 IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE,
1363 &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1364 Request->Data.WriteConsoleOutputAttribRequest.Length +
1366 if( !NT_SUCCESS( Status ) )
1367 DPRINT1( "Failed to write output attributes to console\n" );
1369 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1370 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.Y = ( Buff->CurrentY + Buff->MaxY - Buff->ShowY ) % Buff->MaxY;
1374 return Reply->Status = STATUS_SUCCESS;
1377 CSR_API(CsrFillOutputAttrib)
1380 PCSRSS_SCREEN_BUFFER Buff;
1383 IO_STATUS_BLOCK Iosb;
1384 OUTPUT_ATTRIBUTE Attr;
1386 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1387 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1388 sizeof(LPC_MESSAGE);
1390 Status = CsrGetObject( ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1391 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1393 Reply->Status = Status;
1399 Buff->CurrentX = Request->Data.FillOutputAttribRequest.Coord.X + Buff->ShowX;
1400 Buff->CurrentY = Request->Data.FillOutputAttribRequest.Coord.Y + Buff->ShowY;
1401 for( c = 0; c < Request->Data.FillOutputAttribRequest.Length; c++ )
1403 Buff->Buffer[(Buff->CurrentY * Buff->MaxX * 2) + (Buff->CurrentX * 2) + 1] = Request->Data.FillOutputAttribRequest.Attribute;
1404 if( ++Buff->CurrentX == Buff->MaxX )
1407 if( ++Buff->CurrentY == Buff->MaxY )
1411 if( Buff == ActiveConsole->ActiveBuffer )
1413 Attr.wAttribute = Request->Data.FillOutputAttribRequest.Attribute;
1414 Attr.nLength = Request->Data.FillOutputAttribRequest.Length;
1415 Attr.dwCoord = Request->Data.FillOutputAttribRequest.Coord;
1416 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1421 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE,
1426 if( !NT_SUCCESS( Status ) )
1427 DPRINT1( "Failed to fill output attribute\n" );
1432 return Reply->Status = STATUS_SUCCESS;
1436 CSR_API(CsrGetCursorInfo)
1438 PCSRSS_SCREEN_BUFFER Buff;
1441 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1442 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1443 sizeof(LPC_MESSAGE);
1445 Status = CsrGetObject( ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1446 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1448 Reply->Status = Status;
1452 Reply->Data.GetCursorInfoReply.Info = Buff->CursorInfo;
1454 return Reply->Status = STATUS_SUCCESS;
1457 CSR_API(CsrSetCursorInfo)
1459 PCSRSS_SCREEN_BUFFER Buff;
1461 IO_STATUS_BLOCK Iosb;
1463 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1464 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1465 sizeof(LPC_MESSAGE);
1467 Status = CsrGetObject( ProcessData,
1468 Request->Data.SetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1470 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1472 Reply->Status = Status;
1476 Buff->CursorInfo = Request->Data.SetCursorInfoRequest.Info;
1477 if( Buff == ActiveConsole->ActiveBuffer )
1479 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_CURSOR_INFO, &Buff->CursorInfo, sizeof( Buff->CursorInfo ), 0, 0 );
1480 if( !NT_SUCCESS( Status ) )
1482 DbgPrint( "CSR: Failed to set cursor info\n" );
1483 return Reply->Status = Status;
1487 return Reply->Status = STATUS_SUCCESS;
1490 CSR_API(CsrSetTextAttrib)
1493 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
1494 IO_STATUS_BLOCK Iosb;
1495 PCSRSS_SCREEN_BUFFER Buff;
1497 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1498 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1499 sizeof(LPC_MESSAGE);
1501 Status = CsrGetObject( ProcessData, Request->Data.SetAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1502 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1504 Reply->Status = Status;
1508 Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1509 if( Buff == ActiveConsole->ActiveBuffer )
1511 ScrInfo.wAttributes = Buff->DefaultAttrib;
1512 ScrInfo.dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1513 ScrInfo.dwCursorPosition.Y = ((Buff->CurrentY + Buff->MaxY) - Buff->ShowY) % Buff->MaxY;
1514 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
1515 if( !NT_SUCCESS( Status ) )
1517 DbgPrint( "CSR: Failed to set console info\n" );
1519 return Reply->Status = Status;
1523 return Reply->Status = STATUS_SUCCESS;
1526 CSR_API(CsrSetConsoleMode)
1529 PCSRSS_CONSOLE Console;
1530 PCSRSS_SCREEN_BUFFER Buff;
1532 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1533 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1535 Status = CsrGetObject( ProcessData,
1536 Request->Data.SetConsoleModeRequest.ConsoleHandle,
1537 (Object_t **)&Console );
1538 if( !NT_SUCCESS( Status ) )
1540 Reply->Status = Status;
1545 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1546 if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1547 Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1548 else if( Console->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1549 Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1551 Reply->Status = STATUS_INVALID_HANDLE;
1556 Reply->Status = STATUS_SUCCESS;
1557 return Reply->Status;
1560 CSR_API(CsrGetConsoleMode)
1563 PCSRSS_CONSOLE Console;
1564 PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
1566 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1567 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1569 Status = CsrGetObject( ProcessData,
1570 Request->Data.GetConsoleModeRequest.ConsoleHandle,
1571 (Object_t **)&Console );
1572 if( !NT_SUCCESS( Status ) )
1574 Reply->Status = Status;
1578 Reply->Status = STATUS_SUCCESS;
1579 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1580 if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1581 Reply->Data.GetConsoleModeReply.ConsoleMode = Console->Mode;
1582 else if( Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1583 Reply->Data.GetConsoleModeReply.ConsoleMode = Buff->Mode;
1584 else Status = STATUS_INVALID_HANDLE;
1586 return Reply->Status;
1589 CSR_API(CsrCreateScreenBuffer)
1591 PCSRSS_SCREEN_BUFFER Buff = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
1594 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1595 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1597 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
1599 Status = CsrInitConsoleScreenBuffer( Buff );
1600 if( !NT_SUCCESS( Status ) )
1601 Reply->Status = Status;
1603 Status = CsrInsertObject( ProcessData, &Reply->Data.CreateScreenBufferReply.OutputHandle, &Buff->Header );
1604 if( !NT_SUCCESS( Status ) )
1605 Reply->Status = Status;
1606 else Reply->Status = STATUS_SUCCESS;
1609 return Reply->Status;
1612 CSR_API(CsrSetScreenBuffer)
1615 PCSRSS_SCREEN_BUFFER Buff;
1617 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1618 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1620 Status = CsrGetObject( ProcessData, Request->Data.SetActiveScreenBufferRequest.OutputHandle, (Object_t **)&Buff );
1621 if( !NT_SUCCESS( Status ) )
1622 Reply->Status = Status;
1624 // drop reference to old buffer, maybe delete
1625 if( !InterlockedDecrement( &ProcessData->Console->ActiveBuffer->Header.ReferenceCount ) )
1626 CsrDeleteScreenBuffer( ProcessData->Console->ActiveBuffer );
1627 // tie console to new buffer
1628 ProcessData->Console->ActiveBuffer = Buff;
1629 // inc ref count on new buffer
1630 InterlockedIncrement( &Buff->Header.ReferenceCount );
1631 // if the console is active, redraw it
1632 if( ActiveConsole == ProcessData->Console )
1633 CsrDrawConsole( Buff );
1634 Reply->Status = STATUS_SUCCESS;
1637 return Reply->Status;
1640 CSR_API(CsrSetTitle)
1643 PCSRSS_CONSOLE Console;
1645 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1646 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1648 Status = CsrGetObject( ProcessData, Request->Data.SetTitleRequest.Console, (Object_t **)&Console );
1649 if( !NT_SUCCESS( Status ) )
1650 Reply->Status = Status;
1652 // copy title to console
1653 RtlFreeUnicodeString( &Console->Title );
1654 RtlCreateUnicodeString( &Console->Title, Request->Data.SetTitleRequest.Title );
1655 Reply->Status = STATUS_SUCCESS;
1658 return Reply->Status;
1661 CSR_API(CsrGetTitle)
1664 PCSRSS_CONSOLE Console;
1666 Reply->Header.MessageSize = sizeof (CSRSS_API_REPLY);
1667 Reply->Header.DataSize =
1668 sizeof (CSRSS_API_REPLY)
1669 - sizeof(LPC_MESSAGE);
1671 Status = CsrGetObject (
1673 Request->Data.GetTitleRequest.ConsoleHandle,
1674 (Object_t **) & Console
1676 if ( !NT_SUCCESS( Status ) )
1678 Reply->Status = Status;
1682 HANDLE ConsoleHandle = Request->Data.GetTitleRequest.ConsoleHandle;
1684 /* Copy title of the console to the user title buffer */
1686 & Reply->Data.GetTitleReply,
1687 sizeof (CSRSS_GET_TITLE_REPLY)
1689 Reply->Data.GetTitleReply.ConsoleHandle = ConsoleHandle;
1690 Reply->Data.GetTitleReply.Length = Console->Title.Length;
1691 wcscpy (Reply->Data.GetTitleReply.Title, Console->Title.Buffer);
1692 Reply->Status = STATUS_SUCCESS;
1695 return Reply->Status;
1698 CSR_API(CsrWriteConsoleOutput)
1700 SHORT i, X, Y, SizeX, SizeY;
1701 PCSRSS_SCREEN_BUFFER Buff;
1702 SMALL_RECT ScreenBuffer;
1703 CHAR_INFO* CurCharInfo;
1704 SMALL_RECT WriteRegion;
1705 CHAR_INFO* CharInfo;
1712 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1713 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1715 Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputRequest.ConsoleHandle, (Object_t **)&Buff );
1716 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1718 Reply->Status = Status;
1723 BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
1724 PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
1725 BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
1726 CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
1727 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
1728 (((PVOID)CharInfo + PSize) >
1729 (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
1732 Reply->Status = STATUS_ACCESS_VIOLATION;
1733 return(Reply->Status);
1735 WriteRegion = Request->Data.WriteConsoleOutputRequest.WriteRegion;
1737 SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(WriteRegion));
1738 SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(WriteRegion));
1739 WriteRegion.Bottom = WriteRegion.Top + SizeY;
1740 WriteRegion.Right = WriteRegion.Left + SizeX;
1742 /* Make sure WriteRegion is inside the screen buffer */
1743 CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1744 if (!CsrpGetIntersection(&WriteRegion, ScreenBuffer, WriteRegion))
1747 /* It is okay to have a WriteRegion completely outside the screen buffer.
1748 No data is written then. */
1749 return (Reply->Status = STATUS_SUCCESS);
1752 for ( i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++ )
1754 CurCharInfo = CharInfo + (i * BufferSize.Y);
1755 Offset = (Y * Buff->MaxX + WriteRegion.Left) * 2;
1756 for ( X = WriteRegion.Left; X <= WriteRegion.Right; X++ )
1758 SET_CELL_BUFFER(Buff, Offset, CurCharInfo->Char.AsciiChar, CurCharInfo->Attributes);
1763 if( Buff == ActiveConsole->ActiveBuffer )
1765 CsrpDrawRegion( ActiveConsole->ActiveBuffer, WriteRegion );
1769 Reply->Data.WriteConsoleOutputReply.WriteRegion.Right = WriteRegion.Left + SizeX - 1;
1770 Reply->Data.WriteConsoleOutputReply.WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
1771 Reply->Data.WriteConsoleOutputReply.WriteRegion.Left = WriteRegion.Left;
1772 Reply->Data.WriteConsoleOutputReply.WriteRegion.Top = WriteRegion.Top;
1773 return (Reply->Status = STATUS_SUCCESS);
1776 CSR_API(CsrFlushInputBuffer)
1778 PLIST_ENTRY CurrentEntry;
1779 PLIST_ENTRY NextEntry;
1780 PCSRSS_CONSOLE Console;
1781 ConsoleInput* Input;
1784 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1785 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1787 Status = CsrGetObject( ProcessData, Request->Data.FlushInputBufferRequest.ConsoleInput, (Object_t **)&Console );
1788 if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1790 Reply->Status = Status;
1795 /* Discard all entries in the input event queue */
1796 CurrentEntry = Console->InputEvents.Flink;
1797 while (IsListEmpty(&Console->InputEvents))
1799 NextEntry = CurrentEntry->Flink;
1800 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1801 /* Destroy the event */
1802 Console->WaitingChars--;
1803 RtlFreeHeap( CsrssApiHeap, 0, Input );
1804 CurrentEntry = NextEntry;
1808 return (Reply->Status = STATUS_SUCCESS);
1811 CSR_API(CsrScrollConsoleScreenBuffer)
1813 SHORT i, X, Y, SizeX, SizeY;
1814 PCSRSS_SCREEN_BUFFER Buff;
1815 SMALL_RECT ScreenBuffer;
1816 SMALL_RECT SrcRegion;
1817 SMALL_RECT DstRegion;
1818 SMALL_RECT FillRegion;
1819 IO_STATUS_BLOCK Iosb;
1820 CHAR_INFO* CharInfo;
1826 ALIAS(ConsoleHandle,Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle);
1827 ALIAS(ScrollRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle);
1828 ALIAS(UseClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle);
1829 ALIAS(ClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle);
1830 ALIAS(DestinationOrigin,Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin);
1831 ALIAS(Fill,Request->Data.ScrollConsoleScreenBufferRequest.Fill);
1833 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1834 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1836 Status = CsrGetObject( ProcessData, ConsoleHandle, (Object_t **)&Buff );
1837 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1839 Reply->Status = Status;
1844 /* Make sure source rectangle is inside the screen buffer */
1845 CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1846 if (!CsrpGetIntersection(&SrcRegion, ScreenBuffer, ScrollRectangle))
1849 return (Reply->Status = STATUS_INVALID_PARAMETER);
1852 if (UseClipRectangle)
1854 if (!CsrpGetIntersection(&SrcRegion, SrcRegion, ClipRectangle))
1857 return (Reply->Status = STATUS_SUCCESS);
1864 DestinationOrigin.Y,
1865 DestinationOrigin.X,
1866 DestinationOrigin.Y + CsrpRectHeight(ScrollRectangle) - 1,
1867 DestinationOrigin.X + CsrpRectWidth(ScrollRectangle) - 1)
1869 /* Make sure destination rectangle is inside the screen buffer */
1870 if (!CsrpGetIntersection(&DstRegion, DstRegion, ScreenBuffer))
1873 return (Reply->Status = STATUS_INVALID_PARAMETER);
1876 CsrpCopyRegion(Buff, SrcRegion, DstRegion);
1879 /* Get the region that should be filled with the specified character and attributes */
1883 CsrpGetUnion(&FillRegion, SrcRegion, DstRegion);
1885 if (CsrpSubtractRect(&FillRegion, FillRegion, DstRegion))
1887 /* FIXME: The subtracted rectangle is off by one line */
1888 FillRegion.Top += 1;
1890 CsrpFillRegion(Buff, FillRegion, Fill);
1894 if (Buff == ActiveConsole->ActiveBuffer)
1896 /* Draw destination region */
1897 CsrpDrawRegion(ActiveConsole->ActiveBuffer, DstRegion);
1901 /* Draw filled region */
1902 CsrpDrawRegion(ActiveConsole->ActiveBuffer, FillRegion);
1907 return(Reply->Status = STATUS_SUCCESS);
1911 CSR_API(CsrReadConsoleOutputChar)
1914 PCSRSS_SCREEN_BUFFER ScreenBuffer;
1919 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1920 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
1921 ReadBuffer = Reply->Data.ReadConsoleOutputCharReply.String;
1925 Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
1926 if (!NT_SUCCESS(Status))
1928 Reply->Status = Status;
1930 return(Reply->Status);
1933 if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
1935 Reply->Status = STATUS_INVALID_HANDLE;
1937 return(Reply->Status);
1940 Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X + ScreenBuffer->ShowX;
1941 Ypos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + ScreenBuffer->ShowY;
1943 for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
1945 *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX)];
1950 if (Xpos == ScreenBuffer->MaxX)
1955 if (Ypos == ScreenBuffer->MaxY)
1962 Reply->Status = STATUS_SUCCESS;
1963 Reply->Data.ReadConsoleOutputCharReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
1964 Reply->Data.ReadConsoleOutputCharReply.EndCoord.Y = Ypos - ScreenBuffer->ShowY;
1965 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
1966 Reply->Header.DataSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
1970 return(Reply->Status);
1974 CSR_API(CsrReadConsoleOutputAttrib)
1977 PCSRSS_SCREEN_BUFFER ScreenBuffer;
1982 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1983 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
1984 ReadBuffer = Reply->Data.ReadConsoleOutputAttribReply.String;
1988 Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
1989 if (!NT_SUCCESS(Status))
1991 Reply->Status = Status;
1993 return(Reply->Status);
1996 if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
1998 Reply->Status = STATUS_INVALID_HANDLE;
2000 return(Reply->Status);
2003 Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X + ScreenBuffer->ShowX;
2004 Ypos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + ScreenBuffer->ShowY;
2006 for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2008 *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX) + 1];
2013 if (Xpos == ScreenBuffer->MaxX)
2018 if (Ypos == ScreenBuffer->MaxY)
2025 Reply->Status = STATUS_SUCCESS;
2026 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
2027 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.Y = Ypos - ScreenBuffer->ShowY;
2028 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2029 Reply->Header.DataSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2033 return(Reply->Status);
2037 CSR_API(CsrGetNumberOfConsoleInputEvents)
2040 PCSRSS_CONSOLE Console;
2041 PLIST_ENTRY CurrentItem;
2044 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2045 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2049 Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2050 if (!NT_SUCCESS(Status))
2052 Reply->Status = Status;
2054 return(Reply->Status);
2057 if (Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2059 Reply->Status = STATUS_INVALID_HANDLE;
2061 return(Reply->Status);
2064 CurrentItem = &Console->InputEvents;
2067 // If there are any events ...
2068 if(CurrentItem->Flink != CurrentItem)
2072 CurrentItem = CurrentItem->Flink;
2074 }while(CurrentItem != &Console->InputEvents);
2079 Reply->Status = STATUS_SUCCESS;
2080 Reply->Data.GetNumInputEventsReply.NumInputEvents = NumEvents;
2082 return Reply->Status;
2086 CSR_API(CsrPeekConsoleInput)
2089 PCSRSS_CONSOLE Console;
2092 PLIST_ENTRY CurrentItem;
2093 PLIST_ENTRY NextItem;
2094 PINPUT_RECORD InputRecord;
2098 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2099 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2103 Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2104 if(!NT_SUCCESS(Status))
2106 Reply->Status = Status;
2108 return Reply->Status;
2111 if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2113 Reply->Status = STATUS_INVALID_HANDLE;
2115 return Reply->Status;
2118 InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2119 Length = Request->Data.PeekConsoleInputRequest.Length;
2120 Size = Length * sizeof(INPUT_RECORD);
2122 if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2123 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2126 Reply->Status = STATUS_ACCESS_VIOLATION;
2127 return Reply->Status ;
2132 if(!IsListEmpty(&Console->InputEvents))
2134 CurrentItem = &Console->InputEvents;
2136 while(NumItems < Length)
2139 Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2140 *InputRecord++ = Item->InputEvent;
2142 if(CurrentItem->Flink == &Console->InputEvents)
2145 CurrentItem = CurrentItem->Flink;
2151 Reply->Status = STATUS_SUCCESS;
2152 Reply->Data.PeekConsoleInputReply.Length = NumItems;
2153 return Reply->Status;
2157 CSR_API(CsrReadConsoleOutput)
2159 PCHAR_INFO CharInfo;
2160 PCHAR_INFO CurCharInfo;
2161 PCSRSS_SCREEN_BUFFER ScreenBuffer;
2168 SMALL_RECT ReadRegion;
2169 SMALL_RECT ScreenRect;
2170 DWORD i, Y, X, Offset;
2172 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2173 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2177 Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2178 if(!NT_SUCCESS(Status))
2180 Reply->Status = Status;
2182 return Reply->Status;
2185 if(ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2187 Reply->Status = STATUS_INVALID_HANDLE;
2189 return Reply->Status;
2192 CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
2193 ReadRegion = Request->Data.ReadConsoleOutputRequest.ReadRegion;
2194 BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
2195 BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
2196 Length = BufferSize.X * BufferSize.Y;
2197 Size = Length * sizeof(INPUT_RECORD);
2199 if(((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
2200 || (((PVOID)CharInfo + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2203 Reply->Status = STATUS_ACCESS_VIOLATION;
2204 return Reply->Status ;
2207 SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(ReadRegion));
2208 SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(ReadRegion));
2209 ReadRegion.Bottom = ReadRegion.Top + SizeY;
2210 ReadRegion.Right = ReadRegion.Left + SizeX;
2212 CsrpInitRect(ScreenRect, 0, 0, ScreenBuffer->MaxY - 1, ScreenBuffer->MaxX - 1);
2213 if (!CsrpGetIntersection(&ReadRegion, ScreenRect, ReadRegion))
2216 Reply->Status = STATUS_SUCCESS;
2217 return Reply->Status;
2220 for(i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
2222 CurCharInfo = CharInfo + (i * BufferSize.Y);
2224 Offset = (Y * ScreenBuffer->MaxX + ReadRegion.Left) * 2;
2225 for(X = ReadRegion.Left; X < ReadRegion.Right; ++X)
2227 CurCharInfo->Char.AsciiChar = GET_CELL_BUFFER(ScreenBuffer, Offset);
2228 CurCharInfo->Attributes = GET_CELL_BUFFER(ScreenBuffer, Offset);
2235 Reply->Status = STATUS_SUCCESS;
2236 Reply->Data.ReadConsoleOutputReply.ReadRegion.Right = ReadRegion.Left + SizeX - 1;
2237 Reply->Data.ReadConsoleOutputReply.ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
2238 Reply->Data.ReadConsoleOutputReply.ReadRegion.Left = ReadRegion.Left;
2239 Reply->Data.ReadConsoleOutputReply.ReadRegion.Top = ReadRegion.Top;
2241 return Reply->Status;
2245 CSR_API(CsrWriteConsoleInput)
2247 PINPUT_RECORD InputRecord;
2248 PCSRSS_CONSOLE Console;
2253 PLIST_ENTRY NextItem;
2254 ConsoleInput* Record;
2256 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2257 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2261 Status = CsrGetObject(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, (Object_t**)&Console);
2262 if(!NT_SUCCESS(Status))
2264 Reply->Status = Status;
2266 return Reply->Status;
2269 if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2271 Reply->Status = STATUS_INVALID_HANDLE;
2273 return Reply->Status;
2276 InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
2277 Length = Request->Data.WriteConsoleInputRequest.Length;
2278 Size = Length * sizeof(INPUT_RECORD);
2280 if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2281 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2284 Reply->Status = STATUS_ACCESS_VIOLATION;
2285 return Reply->Status ;
2288 for(i = 0; i < Length; ++i)
2290 Record = RtlAllocateHeap(CsrssApiHeap, 0, sizeof(ConsoleInput));
2294 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
2295 return Reply->Status;
2298 Record->InputEvent = *InputRecord++;
2299 InsertTailList(&Console->InputEvents, &Record->ListEntry);
2304 Reply->Status = STATUS_SUCCESS;
2305 Reply->Data.WriteConsoleInputReply.Length = i;
2306 return Reply->Status;