1 /* $Id: conio.c,v 1.30 2002/05/07 22:44:23 hbirr Exp $
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
) -
48 sizeof(LPC_MESSAGE_HEADER
);
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
) -
117 sizeof(LPC_MESSAGE_HEADER
);
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
-
138 sizeof(LPC_MESSAGE_HEADER
);
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
+= SrcDelta
;
582 Mode
.dwMode
= ENABLE_PROCESSED_OUTPUT
;
583 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
,
584 IOCTL_CONSOLE_SET_MODE
, &Mode
, sizeof( Mode
), 0, 0 );
585 if( !NT_SUCCESS( Status
) )
587 DbgPrint( "CSR: Failed to set console mode\n" );
590 Status
= CsrpSetConsoleDeviceCursor(
592 ScreenBuffer
->CurrentX
- ScreenBuffer
->ShowX
,
593 ((ScreenBuffer
->CurrentY
+ ScreenBuffer
->MaxY
) - ScreenBuffer
->ShowY
) % ScreenBuffer
->MaxY
);
594 if( !NT_SUCCESS( Status
) )
596 DbgPrint( "CSR: Failed to set console info\n" );
599 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
,
600 IOCTL_CONSOLE_SET_CURSOR_INFO
, &ScreenBuffer
->CursorInfo
,
601 sizeof( ScreenBuffer
->CursorInfo
), 0, 0 );
602 if( !NT_SUCCESS( Status
) )
604 DbgPrint( "CSR: Failed to set cursor info\n" );
610 CSR_API(CsrWriteConsole
)
612 BYTE
*Buffer
= Request
->Data
.WriteConsoleRequest
.Buffer
;
613 PCSRSS_SCREEN_BUFFER Buff
;
615 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
616 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
617 sizeof(LPC_MESSAGE_HEADER
);
620 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleRequest
.ConsoleHandle
,
621 (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
624 return Reply
->Status
= STATUS_INVALID_HANDLE
;
626 CsrpWriteConsole( Buff
, Buffer
, Request
->Data
.WriteConsoleRequest
.NrCharactersToWrite
, TRUE
);
628 return Reply
->Status
= STATUS_SUCCESS
;
632 NTSTATUS STDCALL
CsrInitConsoleScreenBuffer( PCSRSS_SCREEN_BUFFER Console
)
634 Console
->Header
.Type
= CSRSS_SCREEN_BUFFER_MAGIC
;
635 Console
->Header
.ReferenceCount
= 0;
636 Console
->MaxX
= PhysicalConsoleSize
.X
;
637 Console
->MaxY
= PhysicalConsoleSize
.Y
* 2;
640 Console
->CurrentX
= 0;
641 Console
->CurrentY
= 0;
642 Console
->Buffer
= RtlAllocateHeap( CsrssApiHeap
, 0, Console
->MaxX
* Console
->MaxY
* 2 );
643 if( Console
->Buffer
== 0 )
644 return STATUS_INSUFFICIENT_RESOURCES
;
645 Console
->DefaultAttrib
= 0x17;
646 /* initialize buffer to be empty with default attributes */
647 for( ; Console
->CurrentY
< Console
->MaxY
; Console
->CurrentY
++ )
649 ClearLineBuffer (Console
, 0);
651 Console
->CursorInfo
.bVisible
= TRUE
;
652 Console
->CursorInfo
.dwSize
= 5;
653 Console
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
654 Console
->CurrentX
= 0;
655 Console
->CurrentY
= 0;
656 return STATUS_SUCCESS
;
659 VOID STDCALL
CsrDeleteScreenBuffer( PCSRSS_SCREEN_BUFFER Buffer
)
661 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
->Buffer
);
662 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
);
665 NTSTATUS STDCALL
CsrInitConsole(PCSRSS_CONSOLE Console
)
668 OBJECT_ATTRIBUTES ObjectAttributes
;
670 Console
->Title
.MaximumLength
= Console
->Title
.Length
= 0;
671 Console
->Title
.Buffer
= 0;
673 RtlCreateUnicodeString( &Console
->Title
, L
"Command Prompt" );
675 Console
->Header
.ReferenceCount
= 0;
676 Console
->WaitingChars
= 0;
677 Console
->WaitingLines
= 0;
678 Console
->EchoCount
= 0;
679 Console
->Header
.Type
= CSRSS_CONSOLE_MAGIC
;
680 Console
->Mode
= ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
| ENABLE_PROCESSED_INPUT
| ENABLE_MOUSE_INPUT
;
681 Console
->EarlyReturn
= FALSE
;
682 InitializeListHead(&Console
->InputEvents
);
684 InitializeObjectAttributes(&ObjectAttributes
, NULL
, OBJ_INHERIT
, NULL
, NULL
);
686 Status
= NtCreateEvent( &Console
->ActiveEvent
, STANDARD_RIGHTS_ALL
, &ObjectAttributes
, FALSE
, FALSE
);
687 if( !NT_SUCCESS( Status
) )
691 Console
->ActiveBuffer
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_SCREEN_BUFFER
) );
692 if( !Console
->ActiveBuffer
)
694 NtClose( Console
->ActiveEvent
);
695 return STATUS_INSUFFICIENT_RESOURCES
;
697 Status
= CsrInitConsoleScreenBuffer( Console
->ActiveBuffer
);
698 if( !NT_SUCCESS( Status
) )
700 NtClose( Console
->ActiveEvent
);
701 RtlFreeHeap( CsrssApiHeap
, 0, Console
->ActiveBuffer
);
704 /* add a reference count because the buffer is tied to the console */
705 Console
->ActiveBuffer
->Header
.ReferenceCount
++;
706 /* make console active, and insert into console list */
710 Console
->Prev
= ActiveConsole
;
711 Console
->Next
= ActiveConsole
->Next
;
712 ActiveConsole
->Next
->Prev
= Console
;
713 ActiveConsole
->Next
= Console
;
716 Console
->Prev
= Console
;
717 Console
->Next
= Console
;
719 ActiveConsole
= Console
;
720 /* copy buffer contents to screen */
721 CsrDrawConsole( Console
->ActiveBuffer
);
723 return STATUS_SUCCESS
;
726 /***************************************************************
727 * CsrDrawConsole blasts the console buffer onto the screen *
728 * must be called while holding the active console lock *
729 **************************************************************/
730 VOID STDCALL
CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff
)
738 Buff
->ShowY
+ PhysicalConsoleSize
.Y
- 1,
739 Buff
->ShowX
+ PhysicalConsoleSize
.X
- 1);
741 CsrpDrawRegion(Buff
, Region
);
745 VOID STDCALL
CsrDeleteConsole( PCSRSS_CONSOLE Console
)
748 DPRINT( "CsrDeleteConsole\n" );
750 /* Drain input event queue */
751 while( Console
->InputEvents
.Flink
!= &Console
->InputEvents
)
753 Event
= (ConsoleInput
*)Console
->InputEvents
.Flink
;
754 Console
->InputEvents
.Flink
= Console
->InputEvents
.Flink
->Flink
;
755 Console
->InputEvents
.Flink
->Flink
->Blink
= &Console
->InputEvents
;
756 RtlFreeHeap( CsrssApiHeap
, 0, Event
);
758 /* Switch to next console */
759 if( ActiveConsole
== Console
)
761 if( Console
->Next
!= Console
)
763 ActiveConsole
= Console
->Next
;
764 Console
->Prev
->Next
= Console
->Next
;
765 Console
->Next
->Prev
= Console
->Prev
;
767 else ActiveConsole
= 0;
770 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
772 if( !--Console
->ActiveBuffer
->Header
.ReferenceCount
)
773 CsrDeleteScreenBuffer( Console
->ActiveBuffer
);
774 NtClose( Console
->ActiveEvent
);
775 RtlFreeUnicodeString( &Console
->Title
);
776 RtlFreeHeap( CsrssApiHeap
, 0, Console
);
779 VOID STDCALL
CsrInitConsoleSupport(VOID
)
781 OBJECT_ATTRIBUTES ObjectAttributes
;
782 UNICODE_STRING DeviceName
;
784 IO_STATUS_BLOCK Iosb
;
785 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
787 DPRINT("CSR: CsrInitConsoleSupport()\n");
789 RtlInitUnicodeString(&DeviceName
, L
"\\??\\BlueScreen");
790 InitializeObjectAttributes(&ObjectAttributes
,
795 Status
= NtOpenFile(&ConsoleDeviceHandle
,
800 FILE_SYNCHRONOUS_IO_ALERT
);
801 if (!NT_SUCCESS(Status
))
803 DbgPrint("CSR: Failed to open console. Expect problems.\n");
806 RtlInitUnicodeString(&DeviceName
, L
"\\??\\Keyboard");
807 InitializeObjectAttributes(&ObjectAttributes
,
812 Status
= NtOpenFile(&KeyboardDeviceHandle
,
818 if (!NT_SUCCESS(Status
))
820 DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
824 RtlInitializeCriticalSection( &ActiveConsoleLock
);
825 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
, 0, 0, &ScrInfo
, sizeof( ScrInfo
) );
826 if( !NT_SUCCESS( Status
) )
828 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
831 PhysicalConsoleSize
= ScrInfo
.dwSize
;
834 VOID
Console_Api( DWORD RefreshEvent
)
836 /* keep reading events from the keyboard and stuffing them into the current
837 console's input queue */
838 ConsoleInput
*KeyEventRecord
;
839 ConsoleInput
*TempInput
;
840 IO_STATUS_BLOCK Iosb
;
842 HANDLE Events
[2]; // 0 = keyboard, 1 = refresh
845 PCSRSS_CONSOLE SwapConsole
= 0; // console we are thinking about swapping with
848 Status
= NtCreateEvent( &Events
[0], STANDARD_RIGHTS_ALL
, NULL
, FALSE
, FALSE
);
849 if( !NT_SUCCESS( Status
) )
851 DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status
);
852 NtTerminateProcess( NtCurrentProcess(), Status
);
854 Events
[1] = (HANDLE
)RefreshEvent
;
857 KeyEventRecord
= RtlAllocateHeap(CsrssApiHeap
,
859 sizeof(ConsoleInput
));
860 if ( KeyEventRecord
== 0 )
862 DbgPrint( "CSR: Memory allocation failure!" );
865 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
866 Status
= NtReadFile( KeyboardDeviceHandle
, Events
[0], NULL
, NULL
, &Iosb
,
867 &KeyEventRecord
->InputEvent
.Event
.KeyEvent
, sizeof( KEY_EVENT_RECORD
), NULL
, 0 );
868 if( !NT_SUCCESS( Status
) )
870 DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
871 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
874 if( Status
== STATUS_PENDING
)
878 Status
= NtWaitForMultipleObjects( 2, Events
, WaitAny
, FALSE
, NULL
);
879 if( Status
== STATUS_WAIT_0
+ 1 )
882 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
886 else if( Status
!= STATUS_WAIT_0
)
888 DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status
);
889 NtTerminateProcess( NtCurrentProcess(), Status
);
894 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
&
895 ( RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
)&&
896 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_TAB
)
897 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
)
902 unsigned int src
, dst
;
904 /* alt-tab, swap consoles */
905 // move SwapConsole to next console, and print its title
908 SwapConsole
= ActiveConsole
;
910 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
)
911 SwapConsole
= SwapConsole
->Prev
;
912 else SwapConsole
= SwapConsole
->Next
;
913 Title
.MaximumLength
= RtlUnicodeStringToAnsiSize( &SwapConsole
->Title
);
915 Buffer
= RtlAllocateHeap( CsrssApiHeap
,
917 sizeof( COORD
) + Title
.MaximumLength
);
918 pos
= (COORD
*)Buffer
;
919 Title
.Buffer
= Buffer
+ sizeof( COORD
);
921 /* this does not seem to work
922 RtlUnicodeStringToAnsiString( &Title, &SwapConsole->Title, FALSE ); */
924 for( src
= 0, dst
= 0; src
< SwapConsole
->Title
.Length
; src
++, dst
++ )
925 Title
.Buffer
[dst
] = (char)SwapConsole
->Title
.Buffer
[dst
];
927 pos
->Y
= PhysicalConsoleSize
.Y
/ 2;
928 pos
->X
= ( PhysicalConsoleSize
.X
- Title
.MaximumLength
) / 2;
929 // redraw the console to clear off old title
930 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
931 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
936 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
940 sizeof (COORD
) + Title
.MaximumLength
);
941 if( !NT_SUCCESS( Status
) )
943 DPRINT1( "Error writing to console\n" );
945 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
);
948 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
952 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
955 else if( SwapConsole
&&
956 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_MENU
&&
957 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
)
959 // alt key released, swap consoles
963 if( SwapConsole
!= ActiveConsole
)
965 // first remove swapconsole from the list
966 SwapConsole
->Prev
->Next
= SwapConsole
->Next
;
967 SwapConsole
->Next
->Prev
= SwapConsole
->Prev
;
968 // now insert before activeconsole
969 SwapConsole
->Next
= ActiveConsole
;
970 SwapConsole
->Prev
= ActiveConsole
->Prev
;
971 ActiveConsole
->Prev
->Next
= SwapConsole
;
972 ActiveConsole
->Prev
= SwapConsole
;
974 ActiveConsole
= SwapConsole
;
976 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
980 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
&
981 ( RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) &&
982 ( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
||
983 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
) )
985 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
)
987 /* scroll up or down */
989 if( ActiveConsole
== 0 )
991 DbgPrint( "CSR: No Active Console!\n" );
993 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
996 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)
998 /* only scroll up if there is room to scroll up into */
999 if( ActiveConsole
->ActiveBuffer
->ShowY
!= ((ActiveConsole
->ActiveBuffer
->CurrentY
+ 1) %
1000 ActiveConsole
->ActiveBuffer
->MaxY
) )
1001 ActiveConsole
->ActiveBuffer
->ShowY
= (ActiveConsole
->ActiveBuffer
->ShowY
+
1002 ActiveConsole
->ActiveBuffer
->MaxY
- 1) % ActiveConsole
->ActiveBuffer
->MaxY
;
1004 else if( ActiveConsole
->ActiveBuffer
->ShowY
!= ActiveConsole
->ActiveBuffer
->CurrentY
)
1005 /* only scroll down if there is room to scroll down into */
1006 if( ActiveConsole
->ActiveBuffer
->ShowY
% ActiveConsole
->ActiveBuffer
->MaxY
!=
1007 ActiveConsole
->ActiveBuffer
->CurrentY
)
1009 if( ((ActiveConsole
->ActiveBuffer
->CurrentY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
) !=
1010 (ActiveConsole
->ActiveBuffer
->ShowY
+ PhysicalConsoleSize
.Y
) % ActiveConsole
->ActiveBuffer
->MaxY
)
1011 ActiveConsole
->ActiveBuffer
->ShowY
= (ActiveConsole
->ActiveBuffer
->ShowY
+ 1) %
1012 ActiveConsole
->ActiveBuffer
->MaxY
;
1013 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
1016 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
1020 if( ActiveConsole
== 0 )
1022 DbgPrint( "CSR: No Active Console!\n" );
1024 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
1027 // process special keys if enabled
1028 if( ActiveConsole
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
) )
1029 switch( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
1032 // add a \n to the queue as well
1034 updown
= KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
;
1035 KeyEventRecord
->Echoed
= FALSE
;
1036 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\r';
1037 InsertTailList(&ActiveConsole
->InputEvents
, &KeyEventRecord
->ListEntry
);
1038 ActiveConsole
->WaitingChars
++;
1039 KeyEventRecord
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( ConsoleInput
) );
1040 if( !KeyEventRecord
)
1042 DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
1046 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
1047 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
= updown
;
1048 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
= 0;
1049 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualScanCode
= 0;
1050 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\n';
1052 // add event to the queue
1053 InsertTailList(&ActiveConsole
->InputEvents
, &KeyEventRecord
->ListEntry
);
1054 // if line input mode is enabled, only wake the client on enter key down
1055 if( !(ActiveConsole
->Mode
& ENABLE_LINE_INPUT
) ||
1056 ActiveConsole
->EarlyReturn
||
1057 ( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' &&
1058 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
) )
1060 NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
1061 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' )
1062 ActiveConsole
->WaitingLines
++;
1064 KeyEventRecord
->Echoed
= FALSE
;
1065 if( ActiveConsole
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
) &&
1066 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\b' &&
1067 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
)
1069 // walk the input queue looking for a char to backspace
1070 for( TempInput
= (ConsoleInput
*)ActiveConsole
->InputEvents
.Blink
;
1071 TempInput
!= (ConsoleInput
*)&ActiveConsole
->InputEvents
&&
1072 (TempInput
->InputEvent
.EventType
!= KEY_EVENT
||
1073 TempInput
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
||
1074 TempInput
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\b' );
1075 TempInput
= (ConsoleInput
*)TempInput
->ListEntry
.Blink
);
1076 // if we found one, delete it, otherwise, wake the client
1077 if( TempInput
!= (ConsoleInput
*)&ActiveConsole
->InputEvents
)
1079 // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
1080 RemoveEntryList(&TempInput
->ListEntry
);
1081 if( TempInput
->Echoed
)
1082 CsrpWriteConsole( ActiveConsole
->ActiveBuffer
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
1083 RtlFreeHeap( CsrssApiHeap
, 0, TempInput
);
1084 RemoveEntryList(&KeyEventRecord
->ListEntry
);
1085 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
1086 ActiveConsole
->WaitingChars
-= 2;
1088 else NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
1091 // echo chars if we are supposed to and client is waiting for some
1092 if( ( ActiveConsole
->Mode
& ENABLE_ECHO_INPUT
) && ActiveConsole
->EchoCount
&&
1093 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
&&
1094 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
&&
1095 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
!= '\r' )
1097 // mark the char as already echoed
1098 CsrpWriteConsole( ActiveConsole
->ActiveBuffer
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
1099 ActiveConsole
->EchoCount
--;
1100 KeyEventRecord
->Echoed
= TRUE
;
1103 ActiveConsole
->WaitingChars
++;
1104 if( !(ActiveConsole
->Mode
& ENABLE_LINE_INPUT
) )
1105 NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
1110 CSR_API(CsrGetScreenBufferInfo
)
1113 PCSRSS_SCREEN_BUFFER Buff
;
1114 PCONSOLE_SCREEN_BUFFER_INFO pInfo
;
1115 IO_STATUS_BLOCK Iosb
;
1117 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1118 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1119 sizeof(LPC_MESSAGE_HEADER
);
1122 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.ScreenBufferInfoRequest
.ConsoleHandle
,
1123 (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
1126 return Reply
->Status
= STATUS_INVALID_HANDLE
;
1128 pInfo
= &Reply
->Data
.ScreenBufferInfoReply
.Info
;
1129 if( Buff
== ActiveConsole
->ActiveBuffer
)
1131 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
,
1132 IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
, 0, 0, pInfo
, sizeof( *pInfo
) );
1133 if( !NT_SUCCESS( Status
) )
1134 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
1135 Reply
->Status
= Status
;
1138 pInfo
->dwSize
.X
= PhysicalConsoleSize
.X
;
1139 pInfo
->dwSize
.Y
= PhysicalConsoleSize
.Y
;
1140 pInfo
->dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1141 pInfo
->dwCursorPosition
.Y
= (Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
1142 pInfo
->wAttributes
= Buff
->DefaultAttrib
;
1143 pInfo
->srWindow
.Left
= 0;
1144 pInfo
->srWindow
.Right
= PhysicalConsoleSize
.X
- 1;
1145 pInfo
->srWindow
.Top
= 0;
1146 pInfo
->srWindow
.Bottom
= PhysicalConsoleSize
.Y
- 1;
1147 Reply
->Status
= STATUS_SUCCESS
;
1150 return Reply
->Status
;
1153 CSR_API(CsrSetCursor
)
1156 PCSRSS_SCREEN_BUFFER Buff
;
1157 CONSOLE_SCREEN_BUFFER_INFO Info
;
1158 IO_STATUS_BLOCK Iosb
;
1160 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1161 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1162 sizeof(LPC_MESSAGE_HEADER
);
1165 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.SetCursorRequest
.ConsoleHandle
,
1166 (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
1169 return Reply
->Status
= STATUS_INVALID_HANDLE
;
1171 Info
.dwCursorPosition
= Request
->Data
.SetCursorRequest
.Position
;
1172 Info
.wAttributes
= Buff
->DefaultAttrib
;
1173 if( Buff
== ActiveConsole
->ActiveBuffer
)
1175 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
,
1176 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &Info
, sizeof( Info
), 0, 0 );
1177 if( !NT_SUCCESS( Status
) )
1178 DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
1181 Buff
->CurrentX
= Info
.dwCursorPosition
.X
+ Buff
->ShowX
;
1182 Buff
->CurrentY
= (Info
.dwCursorPosition
.Y
+ Buff
->ShowY
) % Buff
->MaxY
;
1184 return Reply
->Status
= Status
;
1187 CSR_API(CsrWriteConsoleOutputChar
)
1189 BYTE
*Buffer
= Request
->Data
.WriteConsoleOutputCharRequest
.String
;
1190 PCSRSS_SCREEN_BUFFER Buff
;
1193 IO_STATUS_BLOCK Iosb
;
1195 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1196 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1197 sizeof(LPC_MESSAGE_HEADER
);
1199 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleOutputCharRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
1202 return Reply
->Status
= STATUS_INVALID_HANDLE
;
1206 Buff
->CurrentX
= Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.X
;
1207 Buff
->CurrentY
= Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.Y
;
1208 Buffer
[Request
->Data
.WriteConsoleOutputCharRequest
.Length
] = 0;
1209 CsrpWriteConsole( Buff
, Buffer
, Request
->Data
.WriteConsoleOutputCharRequest
.Length
, FALSE
);
1210 if( ActiveConsole
->ActiveBuffer
== Buff
)
1212 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
1217 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
1220 &Request
->Data
.WriteConsoleOutputCharRequest
.Coord
,
1221 sizeof (COORD
) + Request
->Data
.WriteConsoleOutputCharRequest
.Length
);
1222 if( !NT_SUCCESS( Status
) )
1223 DPRINT1( "Failed to write output chars: %x\n", Status
);
1225 Reply
->Data
.WriteConsoleOutputCharReply
.EndCoord
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1226 Reply
->Data
.WriteConsoleOutputCharReply
.EndCoord
.Y
= (Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
1230 return Reply
->Status
= STATUS_SUCCESS
;
1233 CSR_API(CsrFillOutputChar
)
1235 PCSRSS_SCREEN_BUFFER Buff
;
1238 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1239 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1240 sizeof(LPC_MESSAGE_HEADER
);
1243 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.FillOutputRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
1246 return Reply
->Status
= STATUS_INVALID_HANDLE
;
1248 X
= Request
->Data
.FillOutputRequest
.Position
.X
+ Buff
->ShowX
;
1249 Y
= Request
->Data
.FillOutputRequest
.Position
.Y
+ Buff
->ShowY
;
1250 for( i
= 0; i
< 20000; i
++ );
1251 for( i
= 0; i
< Request
->Data
.FillOutputRequest
.Length
; i
++ )
1253 Buff
->Buffer
[ (Y
* 2 * Buff
->MaxX
) + (X
* 2) ] = Request
->Data
.FillOutputRequest
.Char
;
1254 if( ++X
== Buff
->MaxX
)
1256 if( ++Y
== Buff
->MaxY
)
1261 if( Buff
== ActiveConsole
->ActiveBuffer
)
1262 CsrDrawConsole( Buff
);
1264 return Reply
->Status
;
1267 CSR_API(CsrReadInputEvent
)
1269 PLIST_ENTRY CurrentEntry
;
1270 PCSRSS_CONSOLE Console
;
1272 ConsoleInput
*Input
;
1274 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1275 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1276 sizeof(LPC_MESSAGE_HEADER
);
1277 Reply
->Data
.ReadInputReply
.Event
= ProcessData
->ConsoleEvent
;
1280 Status
= CsrGetObject( ProcessData
, Request
->Data
.ReadInputRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1281 if( !NT_SUCCESS( Status
) || (Status
= Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1283 Reply
->Status
= Status
;
1288 // only get input if there is any
1289 if( Console
->InputEvents
.Flink
!= &Console
->InputEvents
)
1291 CurrentEntry
= RemoveHeadList(&Console
->InputEvents
);
1292 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
1293 Reply
->Data
.ReadInputReply
.Input
= Input
->InputEvent
;
1295 if( Input
->InputEvent
.EventType
== KEY_EVENT
)
1297 if( Console
->Mode
& ENABLE_LINE_INPUT
&&
1298 Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
&&
1299 Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' )
1300 Console
->WaitingLines
--;
1301 Console
->WaitingChars
--;
1303 RtlFreeHeap( CsrssApiHeap
, 0, Input
);
1304 Reply
->Data
.ReadInputReply
.MoreEvents
= (Console
->InputEvents
.Flink
!= &Console
->InputEvents
) ? TRUE
: FALSE
;
1305 Status
= STATUS_SUCCESS
;
1306 Console
->EarlyReturn
= FALSE
; // clear early return
1309 Status
= STATUS_PENDING
;
1310 Console
->EarlyReturn
= TRUE
; // mark for early return
1313 return Reply
->Status
= Status
;
1316 CSR_API(CsrWriteConsoleOutputAttrib
)
1319 PCSRSS_SCREEN_BUFFER Buff
;
1322 IO_STATUS_BLOCK Iosb
;
1324 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1325 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1326 sizeof(LPC_MESSAGE_HEADER
);
1328 Status
= CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleOutputAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1329 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1331 Reply
->Status
= Status
;
1337 Buff
->CurrentX
= Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.X
+ Buff
->ShowX
;
1338 Buff
->CurrentY
= (Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.Y
+ Buff
->ShowY
) % Buff
->MaxY
;
1339 for( c
= 0; c
< Request
->Data
.WriteConsoleOutputAttribRequest
.Length
; c
++ )
1341 Buff
->Buffer
[(Buff
->CurrentY
* Buff
->MaxX
* 2) + (Buff
->CurrentX
* 2) + 1] = Request
->Data
.WriteConsoleOutputAttribRequest
.String
[c
];
1342 if( ++Buff
->CurrentX
== Buff
->MaxX
)
1345 if( ++Buff
->CurrentY
== Buff
->MaxY
)
1349 if( Buff
== ActiveConsole
->ActiveBuffer
)
1351 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
1356 IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE
,
1359 &Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
,
1360 Request
->Data
.WriteConsoleOutputAttribRequest
.Length
+
1362 if( !NT_SUCCESS( Status
) )
1363 DPRINT1( "Failed to write output attributes to console\n" );
1365 Reply
->Data
.WriteConsoleOutputAttribReply
.EndCoord
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1366 Reply
->Data
.WriteConsoleOutputAttribReply
.EndCoord
.Y
= ( Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
1370 return Reply
->Status
= STATUS_SUCCESS
;
1373 CSR_API(CsrFillOutputAttrib
)
1376 PCSRSS_SCREEN_BUFFER Buff
;
1379 IO_STATUS_BLOCK Iosb
;
1380 OUTPUT_ATTRIBUTE Attr
;
1382 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1383 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1384 sizeof(LPC_MESSAGE_HEADER
);
1386 Status
= CsrGetObject( ProcessData
, Request
->Data
.FillOutputAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1387 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1389 Reply
->Status
= Status
;
1395 Buff
->CurrentX
= Request
->Data
.FillOutputAttribRequest
.Coord
.X
+ Buff
->ShowX
;
1396 Buff
->CurrentY
= Request
->Data
.FillOutputAttribRequest
.Coord
.Y
+ Buff
->ShowY
;
1397 for( c
= 0; c
< Request
->Data
.FillOutputAttribRequest
.Length
; c
++ )
1399 Buff
->Buffer
[(Buff
->CurrentY
* Buff
->MaxX
* 2) + (Buff
->CurrentX
* 2) + 1] = Request
->Data
.FillOutputAttribRequest
.Attribute
;
1400 if( ++Buff
->CurrentX
== Buff
->MaxX
)
1403 if( ++Buff
->CurrentY
== Buff
->MaxY
)
1407 if( Buff
== ActiveConsole
->ActiveBuffer
)
1409 Attr
.wAttribute
= Request
->Data
.FillOutputAttribRequest
.Attribute
;
1410 Attr
.nLength
= Request
->Data
.FillOutputAttribRequest
.Length
;
1411 Attr
.dwCoord
= Request
->Data
.FillOutputAttribRequest
.Coord
;
1412 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
1417 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE
,
1422 if( !NT_SUCCESS( Status
) )
1423 DPRINT1( "Failed to fill output attribute\n" );
1428 return Reply
->Status
= STATUS_SUCCESS
;
1432 CSR_API(CsrGetCursorInfo
)
1434 PCSRSS_SCREEN_BUFFER Buff
;
1437 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1438 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1439 sizeof(LPC_MESSAGE_HEADER
);
1441 Status
= CsrGetObject( ProcessData
, Request
->Data
.GetCursorInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1442 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1444 Reply
->Status
= Status
;
1448 Reply
->Data
.GetCursorInfoReply
.Info
= Buff
->CursorInfo
;
1450 return Reply
->Status
= STATUS_SUCCESS
;
1453 CSR_API(CsrSetCursorInfo
)
1455 PCSRSS_SCREEN_BUFFER Buff
;
1457 IO_STATUS_BLOCK Iosb
;
1459 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1460 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1461 sizeof(LPC_MESSAGE_HEADER
);
1463 Status
= CsrGetObject( ProcessData
,
1464 Request
->Data
.SetCursorInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1466 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1468 Reply
->Status
= Status
;
1472 Buff
->CursorInfo
= Request
->Data
.SetCursorInfoRequest
.Info
;
1473 if( Buff
== ActiveConsole
->ActiveBuffer
)
1475 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_CURSOR_INFO
, &Buff
->CursorInfo
, sizeof( Buff
->CursorInfo
), 0, 0 );
1476 if( !NT_SUCCESS( Status
) )
1478 DbgPrint( "CSR: Failed to set cursor info\n" );
1479 return Reply
->Status
= Status
;
1483 return Reply
->Status
= STATUS_SUCCESS
;
1486 CSR_API(CsrSetTextAttrib
)
1489 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
1490 IO_STATUS_BLOCK Iosb
;
1491 PCSRSS_SCREEN_BUFFER Buff
;
1493 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1494 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1495 sizeof(LPC_MESSAGE_HEADER
);
1497 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1498 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1500 Reply
->Status
= Status
;
1504 Buff
->DefaultAttrib
= Request
->Data
.SetAttribRequest
.Attrib
;
1505 if( Buff
== ActiveConsole
->ActiveBuffer
)
1507 ScrInfo
.wAttributes
= Buff
->DefaultAttrib
;
1508 ScrInfo
.dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1509 ScrInfo
.dwCursorPosition
.Y
= ((Buff
->CurrentY
+ Buff
->MaxY
) - Buff
->ShowY
) % Buff
->MaxY
;
1510 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
1511 if( !NT_SUCCESS( Status
) )
1513 DbgPrint( "CSR: Failed to set console info\n" );
1515 return Reply
->Status
= Status
;
1519 return Reply
->Status
= STATUS_SUCCESS
;
1522 CSR_API(CsrSetConsoleMode
)
1525 PCSRSS_CONSOLE Console
;
1526 PCSRSS_SCREEN_BUFFER Buff
;
1528 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1529 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1531 Status
= CsrGetObject( ProcessData
,
1532 Request
->Data
.SetConsoleModeRequest
.ConsoleHandle
,
1533 (Object_t
**)&Console
);
1534 if( !NT_SUCCESS( Status
) )
1536 Reply
->Status
= Status
;
1541 Buff
= (PCSRSS_SCREEN_BUFFER
)Console
;
1542 if( Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
)
1543 Console
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_INPUT_MODE_VALID
;
1544 else if( Console
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
)
1545 Buff
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_OUTPUT_MODE_VALID
;
1547 Reply
->Status
= STATUS_INVALID_HANDLE
;
1552 Reply
->Status
= STATUS_SUCCESS
;
1553 return Reply
->Status
;
1556 CSR_API(CsrGetConsoleMode
)
1559 PCSRSS_CONSOLE Console
;
1560 PCSRSS_SCREEN_BUFFER Buff
; /* gee, I really wish I could use an anonymous union here */
1562 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1563 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1565 Status
= CsrGetObject( ProcessData
,
1566 Request
->Data
.GetConsoleModeRequest
.ConsoleHandle
,
1567 (Object_t
**)&Console
);
1568 if( !NT_SUCCESS( Status
) )
1570 Reply
->Status
= Status
;
1574 Reply
->Status
= STATUS_SUCCESS
;
1575 Buff
= (PCSRSS_SCREEN_BUFFER
)Console
;
1576 if( Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
)
1577 Reply
->Data
.GetConsoleModeReply
.ConsoleMode
= Console
->Mode
;
1578 else if( Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
)
1579 Reply
->Data
.GetConsoleModeReply
.ConsoleMode
= Buff
->Mode
;
1580 else Status
= STATUS_INVALID_HANDLE
;
1582 return Reply
->Status
;
1585 CSR_API(CsrCreateScreenBuffer
)
1587 PCSRSS_SCREEN_BUFFER Buff
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_SCREEN_BUFFER
) );
1590 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1591 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1593 Reply
->Status
= STATUS_INSUFFICIENT_RESOURCES
;
1595 Status
= CsrInitConsoleScreenBuffer( Buff
);
1596 if( !NT_SUCCESS( Status
) )
1597 Reply
->Status
= Status
;
1599 Status
= CsrInsertObject( ProcessData
, &Reply
->Data
.CreateScreenBufferReply
.OutputHandle
, &Buff
->Header
);
1600 if( !NT_SUCCESS( Status
) )
1601 Reply
->Status
= Status
;
1602 else Reply
->Status
= STATUS_SUCCESS
;
1605 return Reply
->Status
;
1608 CSR_API(CsrSetScreenBuffer
)
1611 PCSRSS_SCREEN_BUFFER Buff
;
1613 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1614 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1616 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetActiveScreenBufferRequest
.OutputHandle
, (Object_t
**)&Buff
);
1617 if( !NT_SUCCESS( Status
) )
1618 Reply
->Status
= Status
;
1620 // drop reference to old buffer, maybe delete
1621 if( !InterlockedDecrement( &ProcessData
->Console
->ActiveBuffer
->Header
.ReferenceCount
) )
1622 CsrDeleteScreenBuffer( ProcessData
->Console
->ActiveBuffer
);
1623 // tie console to new buffer
1624 ProcessData
->Console
->ActiveBuffer
= Buff
;
1625 // inc ref count on new buffer
1626 InterlockedIncrement( &Buff
->Header
.ReferenceCount
);
1627 // if the console is active, redraw it
1628 if( ActiveConsole
== ProcessData
->Console
)
1629 CsrDrawConsole( Buff
);
1630 Reply
->Status
= STATUS_SUCCESS
;
1633 return Reply
->Status
;
1636 CSR_API(CsrSetTitle
)
1639 PCSRSS_CONSOLE Console
;
1641 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1642 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1644 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetTitleRequest
.Console
, (Object_t
**)&Console
);
1645 if( !NT_SUCCESS( Status
) )
1646 Reply
->Status
= Status
;
1648 // copy title to console
1649 RtlFreeUnicodeString( &Console
->Title
);
1650 RtlCreateUnicodeString( &Console
->Title
, Request
->Data
.SetTitleRequest
.Title
);
1651 Reply
->Status
= STATUS_SUCCESS
;
1654 return Reply
->Status
;
1657 CSR_API(CsrGetTitle
)
1660 PCSRSS_CONSOLE Console
;
1662 Reply
->Header
.MessageSize
= sizeof (CSRSS_API_REPLY
);
1663 Reply
->Header
.DataSize
=
1664 sizeof (CSRSS_API_REPLY
)
1665 - sizeof(LPC_MESSAGE_HEADER
);
1667 Status
= CsrGetObject (
1669 Request
->Data
.GetTitleRequest
.ConsoleHandle
,
1670 (Object_t
**) & Console
1672 if ( !NT_SUCCESS( Status
) )
1674 Reply
->Status
= Status
;
1678 HANDLE ConsoleHandle
= Request
->Data
.GetTitleRequest
.ConsoleHandle
;
1680 /* Copy title of the console to the user title buffer */
1682 & Reply
->Data
.GetTitleReply
,
1683 sizeof (CSRSS_GET_TITLE_REPLY
)
1685 Reply
->Data
.GetTitleReply
.ConsoleHandle
= ConsoleHandle
;
1686 Reply
->Data
.GetTitleReply
.Length
= Console
->Title
.Length
;
1687 wcscpy (Reply
->Data
.GetTitleReply
.Title
, Console
->Title
.Buffer
);
1688 Reply
->Status
= STATUS_SUCCESS
;
1691 return Reply
->Status
;
1694 CSR_API(CsrWriteConsoleOutput
)
1696 SHORT i
, X
, Y
, SizeX
, SizeY
;
1697 PCSRSS_SCREEN_BUFFER Buff
;
1698 SMALL_RECT ScreenBuffer
;
1699 CHAR_INFO
* CurCharInfo
;
1700 SMALL_RECT WriteRegion
;
1701 CHAR_INFO
* CharInfo
;
1708 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1709 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1711 Status
= CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleOutputRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1712 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? STATUS_SUCCESS
: STATUS_INVALID_HANDLE
))
1714 Reply
->Status
= Status
;
1719 BufferSize
= Request
->Data
.WriteConsoleOutputRequest
.BufferSize
;
1720 PSize
= BufferSize
.X
* BufferSize
.Y
* sizeof(CHAR_INFO
);
1721 BufferCoord
= Request
->Data
.WriteConsoleOutputRequest
.BufferCoord
;
1722 CharInfo
= Request
->Data
.WriteConsoleOutputRequest
.CharInfo
;
1723 if (((PVOID
)CharInfo
< ProcessData
->CsrSectionViewBase
) ||
1724 (((PVOID
)CharInfo
+ PSize
) >
1725 (ProcessData
->CsrSectionViewBase
+ ProcessData
->CsrSectionViewSize
)))
1728 Reply
->Status
= STATUS_ACCESS_VIOLATION
;
1729 return(Reply
->Status
);
1731 WriteRegion
= Request
->Data
.WriteConsoleOutputRequest
.WriteRegion
;
1733 SizeY
= RtlMin(BufferSize
.Y
- BufferCoord
.Y
, CsrpRectHeight(WriteRegion
));
1734 SizeX
= RtlMin(BufferSize
.X
- BufferCoord
.X
, CsrpRectWidth(WriteRegion
));
1735 WriteRegion
.Bottom
= WriteRegion
.Top
+ SizeY
;
1736 WriteRegion
.Right
= WriteRegion
.Left
+ SizeX
;
1738 /* Make sure WriteRegion is inside the screen buffer */
1739 CsrpInitRect(ScreenBuffer
, 0, 0, Buff
->MaxY
- 1, Buff
->MaxX
- 1);
1740 if (!CsrpGetIntersection(&WriteRegion
, ScreenBuffer
, WriteRegion
))
1743 /* It is okay to have a WriteRegion completely outside the screen buffer.
1744 No data is written then. */
1745 return (Reply
->Status
= STATUS_SUCCESS
);
1748 for ( i
= 0, Y
= WriteRegion
.Top
; Y
<= WriteRegion
.Bottom
; i
++, Y
++ )
1750 CurCharInfo
= CharInfo
+ (i
* BufferSize
.Y
);
1751 Offset
= (Y
* Buff
->MaxX
+ WriteRegion
.Left
) * 2;
1752 for ( X
= WriteRegion
.Left
; X
<= WriteRegion
.Right
; X
++ )
1754 SET_CELL_BUFFER(Buff
, Offset
, CurCharInfo
->Char
.AsciiChar
, CurCharInfo
->Attributes
);
1759 if( Buff
== ActiveConsole
->ActiveBuffer
)
1761 CsrpDrawRegion( ActiveConsole
->ActiveBuffer
, WriteRegion
);
1765 Reply
->Data
.WriteConsoleOutputReply
.WriteRegion
.Right
= WriteRegion
.Left
+ SizeX
- 1;
1766 Reply
->Data
.WriteConsoleOutputReply
.WriteRegion
.Bottom
= WriteRegion
.Top
+ SizeY
- 1;
1767 return (Reply
->Status
= STATUS_SUCCESS
);
1770 CSR_API(CsrFlushInputBuffer
)
1772 PLIST_ENTRY CurrentEntry
;
1773 PLIST_ENTRY NextEntry
;
1774 PCSRSS_CONSOLE Console
;
1775 ConsoleInput
* Input
;
1778 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1779 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1781 Status
= CsrGetObject( ProcessData
, Request
->Data
.FlushInputBufferRequest
.ConsoleInput
, (Object_t
**)&Console
);
1782 if( !NT_SUCCESS( Status
) || (Status
= Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
? STATUS_SUCCESS
: STATUS_INVALID_HANDLE
))
1784 Reply
->Status
= Status
;
1789 /* Discard all entries in the input event queue */
1790 CurrentEntry
= Console
->InputEvents
.Flink
;
1791 while (IsListEmpty(&Console
->InputEvents
))
1793 NextEntry
= CurrentEntry
->Flink
;
1794 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
1795 /* Destroy the event */
1796 Console
->WaitingChars
--;
1797 RtlFreeHeap( CsrssApiHeap
, 0, Input
);
1798 CurrentEntry
= NextEntry
;
1802 return (Reply
->Status
= STATUS_SUCCESS
);
1805 CSR_API(CsrScrollConsoleScreenBuffer
)
1807 SHORT i
, X
, Y
, SizeX
, SizeY
;
1808 PCSRSS_SCREEN_BUFFER Buff
;
1809 SMALL_RECT ScreenBuffer
;
1810 SMALL_RECT SrcRegion
;
1811 SMALL_RECT DstRegion
;
1812 SMALL_RECT FillRegion
;
1813 IO_STATUS_BLOCK Iosb
;
1814 CHAR_INFO
* CharInfo
;
1820 ALIAS(ConsoleHandle
,Request
->Data
.ScrollConsoleScreenBufferRequest
.ConsoleHandle
);
1821 ALIAS(ScrollRectangle
,Request
->Data
.ScrollConsoleScreenBufferRequest
.ScrollRectangle
);
1822 ALIAS(UseClipRectangle
,Request
->Data
.ScrollConsoleScreenBufferRequest
.UseClipRectangle
);
1823 ALIAS(ClipRectangle
,Request
->Data
.ScrollConsoleScreenBufferRequest
.ClipRectangle
);
1824 ALIAS(DestinationOrigin
,Request
->Data
.ScrollConsoleScreenBufferRequest
.DestinationOrigin
);
1825 ALIAS(Fill
,Request
->Data
.ScrollConsoleScreenBufferRequest
.Fill
);
1827 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1828 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1830 Status
= CsrGetObject( ProcessData
, ConsoleHandle
, (Object_t
**)&Buff
);
1831 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? STATUS_SUCCESS
: STATUS_INVALID_HANDLE
))
1833 Reply
->Status
= Status
;
1838 /* Make sure source rectangle is inside the screen buffer */
1839 CsrpInitRect(ScreenBuffer
, 0, 0, Buff
->MaxY
- 1, Buff
->MaxX
- 1);
1840 if (!CsrpGetIntersection(&SrcRegion
, ScreenBuffer
, ScrollRectangle
))
1843 return (Reply
->Status
= STATUS_INVALID_PARAMETER
);
1846 if (UseClipRectangle
)
1848 if (!CsrpGetIntersection(&SrcRegion
, SrcRegion
, ClipRectangle
))
1851 return (Reply
->Status
= STATUS_SUCCESS
);
1858 DestinationOrigin
.Y
,
1859 DestinationOrigin
.X
,
1860 DestinationOrigin
.Y
+ CsrpRectHeight(ScrollRectangle
) - 1,
1861 DestinationOrigin
.X
+ CsrpRectWidth(ScrollRectangle
) - 1)
1863 /* Make sure destination rectangle is inside the screen buffer */
1864 if (!CsrpGetIntersection(&DstRegion
, DstRegion
, ScreenBuffer
))
1867 return (Reply
->Status
= STATUS_INVALID_PARAMETER
);
1870 CsrpCopyRegion(Buff
, SrcRegion
, DstRegion
);
1873 /* Get the region that should be filled with the specified character and attributes */
1877 CsrpGetUnion(&FillRegion
, SrcRegion
, DstRegion
);
1879 if (CsrpSubtractRect(&FillRegion
, FillRegion
, DstRegion
))
1881 /* FIXME: The subtracted rectangle is off by one line */
1882 FillRegion
.Top
+= 1;
1884 CsrpFillRegion(Buff
, FillRegion
, Fill
);
1888 if( Buff
== ActiveConsole
->ActiveBuffer
)
1890 /* Draw destination region */
1891 CsrpDrawRegion(ActiveConsole
->ActiveBuffer
, DstRegion
);
1895 /* Draw filled region */
1896 CsrpDrawRegion(ActiveConsole
->ActiveBuffer
, FillRegion
);
1901 return (Reply
->Status
= STATUS_SUCCESS
);