1 /* $Id: conio.c,v 1.20 2001/07/30 11:56:54 ea 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>
20 #define LOCK RtlEnterCriticalSection(&ActiveConsoleLock)
21 #define UNLOCK RtlLeaveCriticalSection(&ActiveConsoleLock)
23 /* GLOBALS *******************************************************************/
25 static HANDLE ConsoleDeviceHandle
;
26 static HANDLE KeyboardDeviceHandle
;
27 static PCSRSS_CONSOLE ActiveConsole
;
28 CRITICAL_SECTION ActiveConsoleLock
;
29 static COORD PhysicalConsoleSize
;
31 /* FUNCTIONS *****************************************************************/
33 NTSTATUS
CsrAllocConsole(PCSRSS_PROCESS_DATA ProcessData
,
34 PCSRSS_API_REQUEST LpcMessage
,
35 PCSRSS_API_REPLY LpcReply
)
37 PCSRSS_CONSOLE Console
;
42 LpcReply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
43 LpcReply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
44 sizeof(LPC_MESSAGE_HEADER
);
45 if( ProcessData
->Console
)
47 LpcReply
->Status
= STATUS_INVALID_PARAMETER
;
48 return STATUS_INVALID_PARAMETER
;
50 LpcReply
->Status
= STATUS_SUCCESS
;
51 Console
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_CONSOLE
) );
54 LpcReply
->Status
= STATUS_INSUFFICIENT_RESOURCES
;
55 return STATUS_INSUFFICIENT_RESOURCES
;
57 LpcReply
->Status
= CsrInitConsole( Console
);
58 if( !NT_SUCCESS( LpcReply
->Status
) )
60 RtlFreeHeap( CsrssApiHeap
, 0, Console
);
61 return LpcReply
->Status
;
63 ProcessData
->Console
= Console
;
64 /* add a reference count because the process is tied to the console */
65 Console
->Header
.ReferenceCount
++;
66 Status
= CsrInsertObject( ProcessData
, &LpcReply
->Data
.AllocConsoleReply
.InputHandle
, &Console
->Header
);
67 if( !NT_SUCCESS( Status
) )
69 CsrDeleteConsole( Console
);
70 ProcessData
->Console
= 0;
71 return LpcReply
->Status
= Status
;
73 Status
= CsrInsertObject( ProcessData
, &LpcReply
->Data
.AllocConsoleReply
.OutputHandle
, &Console
->ActiveBuffer
->Header
);
74 if( !NT_SUCCESS( Status
) )
76 Console
->Header
.ReferenceCount
--;
77 CsrReleaseObject( ProcessData
, LpcReply
->Data
.AllocConsoleReply
.InputHandle
);
78 ProcessData
->Console
= 0;
79 return LpcReply
->Status
= Status
;
81 ClientId
.UniqueProcess
= (HANDLE
)ProcessData
->ProcessId
;
82 Status
= NtOpenProcess( &Process
, PROCESS_DUP_HANDLE
, 0, &ClientId
);
83 if( !NT_SUCCESS( Status
) )
85 DbgPrint( "CSR: NtOpenProcess() failed for handle duplication\n" );
86 Console
->Header
.ReferenceCount
--;
87 ProcessData
->Console
= 0;
88 CsrReleaseObject( ProcessData
, LpcReply
->Data
.AllocConsoleReply
.OutputHandle
);
89 CsrReleaseObject( ProcessData
, LpcReply
->Data
.AllocConsoleReply
.InputHandle
);
90 LpcReply
->Status
= Status
;
93 Status
= NtDuplicateObject( NtCurrentProcess(), &ProcessData
->Console
->ActiveEvent
, Process
, &ProcessData
->ConsoleEvent
, SYNCHRONIZE
, FALSE
, 0 );
94 if( !NT_SUCCESS( Status
) )
96 DbgPrint( "CSR: NtDuplicateObject() failed: %x\n", Status
);
98 Console
->Header
.ReferenceCount
--;
99 CsrReleaseObject( ProcessData
, LpcReply
->Data
.AllocConsoleReply
.OutputHandle
);
100 CsrReleaseObject( ProcessData
, LpcReply
->Data
.AllocConsoleReply
.InputHandle
);
101 ProcessData
->Console
= 0;
102 LpcReply
->Status
= Status
;
106 return STATUS_SUCCESS
;
109 NTSTATUS
CsrFreeConsole(PCSRSS_PROCESS_DATA ProcessData
,
110 PCSRSS_API_REQUEST LpcMessage
,
111 PCSRSS_API_REPLY LpcReply
)
113 LpcReply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
114 LpcReply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
115 sizeof(LPC_MESSAGE_HEADER
);
117 LpcReply
->Status
= STATUS_NOT_IMPLEMENTED
;
119 return(STATUS_NOT_IMPLEMENTED
);
122 NTSTATUS
CsrReadConsole(PCSRSS_PROCESS_DATA ProcessData
,
123 PCSRSS_API_REQUEST LpcMessage
,
124 PCSRSS_API_REPLY LpcReply
)
129 ULONG nNumberOfCharsToRead
;
130 PCSRSS_CONSOLE Console
;
133 /* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
134 nNumberOfCharsToRead
= LpcMessage
->Data
.ReadConsoleRequest
.NrCharactersToRead
> CSRSS_MAX_READ_CONSOLE_REQUEST
? CSRSS_MAX_READ_CONSOLE_REQUEST
: LpcMessage
->Data
.ReadConsoleRequest
.NrCharactersToRead
;
135 LpcReply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
136 LpcReply
->Header
.DataSize
= LpcReply
->Header
.MessageSize
-
137 sizeof(LPC_MESSAGE_HEADER
);
138 Buffer
= LpcReply
->Data
.ReadConsoleReply
.Buffer
;
139 LpcReply
->Data
.ReadConsoleReply
.EventHandle
= ProcessData
->ConsoleEvent
;
141 Status
= CsrGetObject( ProcessData
, LpcMessage
->Data
.ReadConsoleRequest
.ConsoleHandle
, (Object_t
**)&Console
);
142 if( !NT_SUCCESS( Status
) )
144 LpcReply
->Status
= Status
;
148 if( Console
->Header
.Type
!= CSRSS_CONSOLE_MAGIC
)
150 LpcReply
->Status
= STATUS_INVALID_HANDLE
;
152 return STATUS_INVALID_HANDLE
;
154 for (; i
<nNumberOfCharsToRead
&& Console
->InputEvents
.Flink
!= &Console
->InputEvents
; i
++ )
156 // remove input event from queue
157 Input
= (ConsoleInput
*)Console
->InputEvents
.Flink
;
159 Input
->ListEntry
.Blink
->Flink
= Input
->ListEntry
.Flink
;
160 Input
->ListEntry
.Flink
->Blink
= Input
->ListEntry
.Blink
;
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
|| LpcMessage
->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 LpcReply
->Data
.ReadConsoleReply
.NrCharactersRead
= 0;
177 LpcReply
->Status
= STATUS_NOTIFY_CLEANUP
;
178 Console
->WaitingChars
--;
179 RtlFreeHeap( CsrssApiHeap
, 0, Input
);
181 return STATUS_NOTIFY_CLEANUP
;
183 LpcMessage
->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 LpcReply
->Data
.ReadConsoleReply
.NrCharactersRead
= i
;
200 LpcReply
->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 LpcReply
->Status
= STATUS_PENDING
; // line buffered, didn't get a complete line
207 Console
->WaitingLines
--;
208 LpcReply
->Status
= STATUS_SUCCESS
; // line buffered, did get a complete line
210 else LpcReply
->Status
= STATUS_SUCCESS
; // not line buffered, did read something
211 if( LpcReply
->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 LpcReply
->Header
.MessageSize
+= i
;
220 return LpcReply
->Status
;
223 #define SET_CELL_BUFFER(b,o,c,a)\
224 (b)->Buffer[(o)++]=(c);\
225 (b)->Buffer[(o)++]=(a);
227 static DWORD FASTCALL
228 ComputeOffsetBuffer (
229 PCSRSS_SCREEN_BUFFER Buff
,
234 /* 2 == sizeof (cell) */
235 return (2 * ((LogicalY
* Buff
->MaxX
) + LogicalX
));
240 PCSRSS_SCREEN_BUFFER Buff
,
245 DWORD LogicalX
= StartX
;
246 DWORD Offset
= ComputeOffsetBuffer (Buff
, LogicalX
, Buff
->CurrentY
);
248 for ( ; LogicalX
< StopX
; LogicalX
++ )
250 /* Fill the cell: Offset is incremented by the macro */
251 SET_CELL_BUFFER(Buff
,Offset
,' ',Buff
->DefaultAttrib
)
255 NTSTATUS
CsrpWriteConsole( PCSRSS_SCREEN_BUFFER Buff
, CHAR
*Buffer
, DWORD Length
, BOOL Attrib
)
257 IO_STATUS_BLOCK Iosb
;
262 for( i
= 0; i
< Length
; i
++ )
264 switch( Buffer
[ i
] )
269 /* slide the viewable screen */
270 if( ((PhysicalConsoleSize
.Y
+ Buff
->ShowY
) % Buff
->MaxY
) == (Buff
->CurrentY
+ 1) % Buff
->MaxY
)
271 if( ++Buff
->ShowY
== (Buff
->MaxY
- 1) )
273 if( ++Buff
->CurrentY
== Buff
->MaxY
)
277 ClearLineBuffer (Buff
, 0, Buff
->MaxX
);
281 if( Buff
->CurrentX
== 0 )
283 /* slide viewable screen up */
284 if( Buff
->ShowY
== Buff
->CurrentY
)
286 if( Buff
->ShowY
== 0 )
287 Buff
->ShowY
= Buff
->MaxY
;
291 /* slide virtual position up */
292 Buff
->CurrentX
= Buff
->MaxX
;
293 if( Buff
->CurrentY
== 0 )
294 Buff
->CurrentY
= Buff
->MaxY
;
300 Offset
= ComputeOffsetBuffer (Buff
, Buff
->CurrentX
, Buff
->CurrentY
);
301 SET_CELL_BUFFER(Buff
,Offset
,' ',Buff
->DefaultAttrib
);
306 Offset
= ComputeOffsetBuffer (Buff
, Buff
->CurrentX
, Buff
->CurrentY
);
307 Buff
->Buffer
[Offset
++] = Buffer
[ i
];
309 Buff
->Buffer
[Offset
] = Buff
->DefaultAttrib
;
311 if( Buff
->CurrentX
== Buff
->MaxX
)
313 /* if end of line, go to next */
315 if( ++Buff
->CurrentY
== Buff
->MaxY
)
317 /* if end of buffer, wrap back to beginning */
320 ClearLineBuffer (Buff
, 0, Buff
->MaxX
);
324 ClearLineBuffer (Buff
, 0, Buff
->MaxX
);
326 /* slide the viewable screen */
327 if( (Buff
->CurrentY
- Buff
->ShowY
) == PhysicalConsoleSize
.Y
)
328 if( ++Buff
->ShowY
== Buff
->MaxY
)
333 if( Buff
== ActiveConsole
->ActiveBuffer
)
334 { /* only write to screen if Console is Active, and not scrolled up */
337 Status
= NtWriteFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, Buffer
, Length
, NULL
, 0);
338 if (!NT_SUCCESS(Status
))
339 DbgPrint("CSR: Write failed\n");
342 return(STATUS_SUCCESS
);
345 NTSTATUS
CsrWriteConsole(PCSRSS_PROCESS_DATA ProcessData
,
346 PCSRSS_API_REQUEST LpcMessage
,
347 PCSRSS_API_REPLY Reply
)
349 BYTE
*Buffer
= LpcMessage
->Data
.WriteConsoleRequest
.Buffer
;
350 PCSRSS_SCREEN_BUFFER Buff
;
352 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
353 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
354 sizeof(LPC_MESSAGE_HEADER
);
357 if( !NT_SUCCESS( CsrGetObject( ProcessData
, LpcMessage
->Data
.WriteConsoleRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
360 return Reply
->Status
= STATUS_INVALID_HANDLE
;
362 CsrpWriteConsole( Buff
, Buffer
, LpcMessage
->Data
.WriteConsoleRequest
.NrCharactersToWrite
, TRUE
);
364 return Reply
->Status
= STATUS_SUCCESS
;
368 NTSTATUS
CsrInitConsoleScreenBuffer( PCSRSS_SCREEN_BUFFER Console
)
370 Console
->Header
.Type
= CSRSS_SCREEN_BUFFER_MAGIC
;
371 Console
->Header
.ReferenceCount
= 0;
372 Console
->MaxX
= PhysicalConsoleSize
.X
;
373 Console
->MaxY
= PhysicalConsoleSize
.Y
* 2;
376 Console
->CurrentX
= 0;
377 Console
->CurrentY
= 0;
378 Console
->Buffer
= RtlAllocateHeap( CsrssApiHeap
, 0, Console
->MaxX
* Console
->MaxY
* 2 );
379 if( Console
->Buffer
== 0 )
380 return STATUS_INSUFFICIENT_RESOURCES
;
381 Console
->DefaultAttrib
= 0x17;
382 /* initialize buffer to be empty with default attributes */
383 for( ; Console
->CurrentY
< Console
->MaxY
; Console
->CurrentY
++ )
385 ClearLineBuffer (Console
, 0, Console
->MaxX
);
387 Console
->CursorInfo
.bVisible
= TRUE
;
388 Console
->CursorInfo
.dwSize
= 5;
389 Console
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
390 Console
->CurrentX
= 0;
391 Console
->CurrentY
= 0;
392 return STATUS_SUCCESS
;
395 VOID
CsrDeleteScreenBuffer( PCSRSS_SCREEN_BUFFER Buffer
)
397 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
->Buffer
);
398 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
);
401 NTSTATUS
CsrInitConsole(PCSRSS_CONSOLE Console
)
405 Console
->Title
.MaximumLength
= Console
->Title
.Length
= 0;
406 Console
->Title
.Buffer
= 0;
408 RtlCreateUnicodeString( &Console
->Title
, L
"Command Prompt" );
410 Console
->Header
.ReferenceCount
= 0;
411 Console
->WaitingChars
= 0;
412 Console
->WaitingLines
= 0;
413 Console
->EchoCount
= 0;
414 Console
->Header
.Type
= CSRSS_CONSOLE_MAGIC
;
415 Console
->Mode
= ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
| ENABLE_PROCESSED_INPUT
| ENABLE_MOUSE_INPUT
;
416 Console
->InputEvents
.Flink
= Console
->InputEvents
.Blink
= &Console
->InputEvents
;
417 Status
= NtCreateEvent( &Console
->ActiveEvent
, STANDARD_RIGHTS_ALL
, 0, FALSE
, FALSE
);
418 if( !NT_SUCCESS( Status
) )
422 Console
->ActiveBuffer
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_SCREEN_BUFFER
) );
423 if( !Console
->ActiveBuffer
)
425 NtClose( Console
->ActiveEvent
);
426 return STATUS_INSUFFICIENT_RESOURCES
;
428 Status
= CsrInitConsoleScreenBuffer( Console
->ActiveBuffer
);
429 if( !NT_SUCCESS( Status
) )
431 NtClose( Console
->ActiveEvent
);
432 RtlFreeHeap( CsrssApiHeap
, 0, Console
->ActiveBuffer
);
435 /* add a reference count because the buffer is tied to the console */
436 Console
->ActiveBuffer
->Header
.ReferenceCount
++;
437 /* make console active, and insert into console list */
441 Console
->Prev
= ActiveConsole
;
442 Console
->Next
= ActiveConsole
->Next
;
443 ActiveConsole
->Next
->Prev
= Console
;
444 ActiveConsole
->Next
= Console
;
447 Console
->Prev
= Console
;
448 Console
->Next
= Console
;
450 ActiveConsole
= Console
;
451 /* copy buffer contents to screen */
452 CsrDrawConsole( Console
->ActiveBuffer
);
454 return STATUS_SUCCESS
;
457 /***************************************************************
458 * CsrDrawConsole blasts the console buffer onto the screen *
459 * must be called while holding the active console lock *
460 **************************************************************/
461 VOID
CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff
)
463 IO_STATUS_BLOCK Iosb
;
465 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
469 /* first set position to 0,0 */
470 ScrInfo
.dwCursorPosition
.X
= 0;
471 ScrInfo
.dwCursorPosition
.Y
= 0;
472 ScrInfo
.wAttributes
= Buff
->DefaultAttrib
;
473 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
474 if( !NT_SUCCESS( Status
) )
476 DbgPrint( "CSR: Failed to set console info\n" );
479 Mode
.dwMode
= 0; /* clear ENABLE_PROCESSED_OUTPUT mode */
480 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_MODE
, &Mode
, sizeof( Mode
), 0, 0 );
481 if( !NT_SUCCESS( Status
) )
483 DbgPrint( "CSR: Failed to set console mode\n" );
486 /* blast out buffer */
487 for( i
= 0, y
= Buff
->ShowY
; i
< PhysicalConsoleSize
.Y
; i
++ )
489 Status
= NtWriteFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, &Buff
->Buffer
[ (Buff
->ShowX
* 2) + (y
* Buff
->MaxX
* 2) ], PhysicalConsoleSize
.X
* 2, 0, 0 );
490 if( !NT_SUCCESS( Status
) )
492 DbgPrint( "CSR: Write to console failed\n" );
495 /* wrap back around the end of the buffer */
496 if( ++y
== Buff
->MaxY
)
499 Mode
.dwMode
= ENABLE_PROCESSED_OUTPUT
;
500 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_MODE
, &Mode
, sizeof( Mode
), 0, 0 );
501 if( !NT_SUCCESS( Status
) )
503 DbgPrint( "CSR: Failed to set console mode\n" );
506 ScrInfo
.dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
507 ScrInfo
.dwCursorPosition
.Y
= ((Buff
->CurrentY
+ Buff
->MaxY
) - Buff
->ShowY
) % Buff
->MaxY
;
508 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
509 if( !NT_SUCCESS( Status
) )
511 DbgPrint( "CSR: Failed to set console info\n" );
514 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_CURSOR_INFO
, &Buff
->CursorInfo
, sizeof( Buff
->CursorInfo
), 0, 0 );
515 if( !NT_SUCCESS( Status
) )
517 DbgPrint( "CSR: Failed to set cursor info\n" );
523 VOID
CsrDeleteConsole( PCSRSS_CONSOLE Console
)
526 DPRINT1( "CsrDeleteConsole\n" );
528 /* Drain input event queue */
529 while( Console
->InputEvents
.Flink
!= &Console
->InputEvents
)
531 Event
= (ConsoleInput
*)Console
->InputEvents
.Flink
;
532 Console
->InputEvents
.Flink
= Console
->InputEvents
.Flink
->Flink
;
533 Console
->InputEvents
.Flink
->Flink
->Blink
= &Console
->InputEvents
;
534 RtlFreeHeap( CsrssApiHeap
, 0, Event
);
536 /* Switch to next console */
537 if( ActiveConsole
== Console
)
539 if( Console
->Next
!= Console
)
541 ActiveConsole
= Console
->Next
;
542 Console
->Prev
->Next
= Console
->Next
;
543 Console
->Next
->Prev
= Console
->Prev
;
545 else ActiveConsole
= 0;
548 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
550 if( !--Console
->ActiveBuffer
->Header
.ReferenceCount
)
551 CsrDeleteScreenBuffer( Console
->ActiveBuffer
);
552 NtClose( Console
->ActiveEvent
);
553 RtlFreeUnicodeString( &Console
->Title
);
554 RtlFreeHeap( CsrssApiHeap
, 0, Console
);
557 VOID
CsrInitConsoleSupport(VOID
)
559 OBJECT_ATTRIBUTES ObjectAttributes
;
560 UNICODE_STRING DeviceName
;
562 IO_STATUS_BLOCK Iosb
;
563 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
565 DbgPrint("CSR: CsrInitConsoleSupport()\n");
567 RtlInitUnicodeString(&DeviceName
, L
"\\??\\BlueScreen");
568 InitializeObjectAttributes(&ObjectAttributes
,
573 Status
= NtOpenFile(&ConsoleDeviceHandle
,
578 FILE_SYNCHRONOUS_IO_ALERT
);
579 if (!NT_SUCCESS(Status
))
581 DbgPrint("CSR: Failed to open console. Expect problems.\n");
583 // DbgPrint("CSR: ConsoleDeviceHandle %x\n", ConsoleDeviceHandle);
585 RtlInitUnicodeString(&DeviceName
, L
"\\??\\Keyboard");
586 InitializeObjectAttributes(&ObjectAttributes
,
591 Status
= NtOpenFile(&KeyboardDeviceHandle
,
597 if (!NT_SUCCESS(Status
))
599 DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
603 RtlInitializeCriticalSection( &ActiveConsoleLock
);
604 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
, 0, 0, &ScrInfo
, sizeof( ScrInfo
) );
605 if( !NT_SUCCESS( Status
) )
607 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
610 PhysicalConsoleSize
= ScrInfo
.dwSize
;
613 VOID
Console_Api( DWORD RefreshEvent
)
615 /* keep reading events from the keyboard and stuffing them into the current
616 console's input queue */
617 ConsoleInput
*KeyEventRecord
;
618 ConsoleInput
*TempInput
;
619 IO_STATUS_BLOCK Iosb
;
621 HANDLE Events
[2]; // 0 = keyboard, 1 = refresh
624 PCSRSS_CONSOLE SwapConsole
= 0; // console we are thinking about swapping with
627 Status
= NtCreateEvent( &Events
[0], STANDARD_RIGHTS_ALL
, NULL
, FALSE
, FALSE
);
628 if( !NT_SUCCESS( Status
) )
630 DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status
);
631 NtTerminateProcess( NtCurrentProcess(), Status
);
633 Events
[1] = (HANDLE
)RefreshEvent
;
636 KeyEventRecord
= RtlAllocateHeap(CsrssApiHeap
,
638 sizeof(ConsoleInput
));
639 if ( KeyEventRecord
== 0 )
641 DbgPrint( "CSR: Memory allocation failure!" );
644 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
645 Status
= NtReadFile( KeyboardDeviceHandle
, Events
[0], NULL
, NULL
, &Iosb
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
, sizeof( KEY_EVENT_RECORD
), NULL
, 0 );
646 if( !NT_SUCCESS( Status
) )
648 DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
649 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
652 if( Status
== STATUS_PENDING
)
656 Status
= NtWaitForMultipleObjects( 2, Events
, WaitAny
, FALSE
, NULL
);
657 if( Status
== STATUS_WAIT_0
+ 1 )
660 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
664 else if( Status
!= STATUS_WAIT_0
)
666 DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status
);
667 NtTerminateProcess( NtCurrentProcess(), Status
);
672 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
& ( RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
)&& KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_TAB
)
673 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
)
678 unsigned int src
, dst
;
680 /* alt-tab, swap consoles */
681 // move SwapConsole to next console, and print its title
684 SwapConsole
= ActiveConsole
;
686 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
)
687 SwapConsole
= SwapConsole
->Prev
;
688 else SwapConsole
= SwapConsole
->Next
;
689 Title
.MaximumLength
= RtlUnicodeStringToAnsiSize( &SwapConsole
->Title
);
691 Buffer
= RtlAllocateHeap( CsrssApiHeap
,
693 sizeof( COORD
) + Title
.MaximumLength
);
694 pos
= (COORD
*)Buffer
;
695 Title
.Buffer
= Buffer
+ sizeof( COORD
);
697 /* this does not seem to work
698 RtlUnicodeStringToAnsiString( &Title, &SwapConsole->Title, FALSE ); */
700 for( src
= 0, dst
= 0; src
< SwapConsole
->Title
.Length
; src
++, dst
++ )
701 Title
.Buffer
[dst
] = (char)SwapConsole
->Title
.Buffer
[dst
];
703 pos
->Y
= PhysicalConsoleSize
.Y
/ 2;
704 pos
->X
= ( PhysicalConsoleSize
.X
- Title
.MaximumLength
) / 2;
705 // redraw the console to clear off old title
706 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
707 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
712 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
716 sizeof (COORD
) + Title
.MaximumLength
);
717 if( !NT_SUCCESS( Status
) )
719 DPRINT1( "Error writing to console\n" );
721 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
);
724 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
728 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
731 else if( SwapConsole
&&
732 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_MENU
&&
733 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
)
735 // alt key released, swap consoles
739 if( SwapConsole
!= ActiveConsole
)
741 // first remove swapconsole from the list
742 SwapConsole
->Prev
->Next
= SwapConsole
->Next
;
743 SwapConsole
->Next
->Prev
= SwapConsole
->Prev
;
744 // now insert before activeconsole
745 SwapConsole
->Next
= ActiveConsole
;
746 SwapConsole
->Prev
= ActiveConsole
->Prev
;
747 ActiveConsole
->Prev
->Next
= SwapConsole
;
748 ActiveConsole
->Prev
= SwapConsole
;
750 ActiveConsole
= SwapConsole
;
752 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
756 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
& ( RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) && (KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
|| KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
) )
758 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
)
760 /* scroll up or down */
762 if( ActiveConsole
== 0 )
764 DbgPrint( "CSR: No Active Console!\n" );
766 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
769 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)
771 /* only scroll up if there is room to scroll up into */
772 if( ActiveConsole
->ActiveBuffer
->ShowY
!= ((ActiveConsole
->ActiveBuffer
->CurrentY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
) )
773 ActiveConsole
->ActiveBuffer
->ShowY
= (ActiveConsole
->ActiveBuffer
->ShowY
+ ActiveConsole
->ActiveBuffer
->MaxY
- 1) % ActiveConsole
->ActiveBuffer
->MaxY
;
775 else if( ActiveConsole
->ActiveBuffer
->ShowY
!= ActiveConsole
->ActiveBuffer
->CurrentY
)
776 /* only scroll down if there is room to scroll down into */
777 if( ActiveConsole
->ActiveBuffer
->ShowY
% ActiveConsole
->ActiveBuffer
->MaxY
!= ActiveConsole
->ActiveBuffer
->CurrentY
)
778 if( ((ActiveConsole
->ActiveBuffer
->CurrentY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
) != (ActiveConsole
->ActiveBuffer
->ShowY
+ PhysicalConsoleSize
.Y
) % ActiveConsole
->ActiveBuffer
->MaxY
)
779 ActiveConsole
->ActiveBuffer
->ShowY
= (ActiveConsole
->ActiveBuffer
->ShowY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
;
780 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
783 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
787 if( ActiveConsole
== 0 )
789 DbgPrint( "CSR: No Active Console!\n" );
791 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
794 // process special keys if enabled
795 if( ActiveConsole
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
) )
796 switch( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
799 // add a \n to the queue as well
801 updown
= KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
;
802 KeyEventRecord
->Echoed
= FALSE
;
803 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\r';
804 KeyEventRecord
->ListEntry
.Flink
= &ActiveConsole
->InputEvents
;
805 KeyEventRecord
->ListEntry
.Blink
= ActiveConsole
->InputEvents
.Blink
;
806 ActiveConsole
->InputEvents
.Blink
->Flink
= &KeyEventRecord
->ListEntry
;
807 ActiveConsole
->InputEvents
.Blink
= &KeyEventRecord
->ListEntry
;
808 ActiveConsole
->WaitingChars
++;
809 KeyEventRecord
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( ConsoleInput
) );
810 if( !KeyEventRecord
)
812 DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
816 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
817 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
= updown
;
818 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
= 0;
819 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualScanCode
= 0;
820 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\n';
822 // add event to the queue
823 KeyEventRecord
->ListEntry
.Flink
= &ActiveConsole
->InputEvents
;
824 KeyEventRecord
->ListEntry
.Blink
= ActiveConsole
->InputEvents
.Blink
;
825 ActiveConsole
->InputEvents
.Blink
->Flink
= &KeyEventRecord
->ListEntry
;
826 ActiveConsole
->InputEvents
.Blink
= &KeyEventRecord
->ListEntry
;
827 // if line input mode is enabled, only wake the client on enter key down
828 if( !(ActiveConsole
->Mode
& ENABLE_LINE_INPUT
) ||
829 ( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' &&
830 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
) )
832 NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
833 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' )
834 ActiveConsole
->WaitingLines
++;
836 KeyEventRecord
->Echoed
= FALSE
;
837 if( ActiveConsole
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
) &&
838 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\b' &&
839 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
)
841 // walk the input queue looking for a char to backspace
842 for( TempInput
= (ConsoleInput
*)ActiveConsole
->InputEvents
.Blink
;
843 TempInput
!= (ConsoleInput
*)&ActiveConsole
->InputEvents
&&
844 (TempInput
->InputEvent
.EventType
!= KEY_EVENT
||
845 TempInput
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
||
846 TempInput
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\b' );
847 TempInput
= (ConsoleInput
*)TempInput
->ListEntry
.Blink
);
848 // if we found one, delete it, otherwise, wake the client
849 if( TempInput
!= (ConsoleInput
*)&ActiveConsole
->InputEvents
)
851 // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
852 TempInput
->ListEntry
.Blink
->Flink
= TempInput
->ListEntry
.Flink
;
853 TempInput
->ListEntry
.Flink
->Blink
= TempInput
->ListEntry
.Blink
;
854 if( TempInput
->Echoed
)
855 CsrpWriteConsole( ActiveConsole
->ActiveBuffer
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
856 RtlFreeHeap( CsrssApiHeap
, 0, TempInput
);
857 KeyEventRecord
->ListEntry
.Blink
->Flink
= KeyEventRecord
->ListEntry
.Flink
;
858 KeyEventRecord
->ListEntry
.Flink
->Blink
= KeyEventRecord
->ListEntry
.Blink
;
859 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
860 ActiveConsole
->WaitingChars
-= 2;
862 else NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
865 // echo chars if we are supposed to and client is waiting for some
866 if( ActiveConsole
->Mode
& ENABLE_ECHO_INPUT
&& ActiveConsole
->EchoCount
&&
867 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
&&
868 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
&&
869 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
!= '\r' )
871 // mark the char as already echoed
872 CsrpWriteConsole( ActiveConsole
->ActiveBuffer
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
873 ActiveConsole
->EchoCount
--;
874 KeyEventRecord
->Echoed
= TRUE
;
877 ActiveConsole
->WaitingChars
++;
878 if( !(ActiveConsole
->Mode
& ENABLE_LINE_INPUT
) )
879 NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
884 NTSTATUS
CsrGetScreenBufferInfo( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
887 PCSRSS_SCREEN_BUFFER Buff
;
888 PCONSOLE_SCREEN_BUFFER_INFO pInfo
;
889 IO_STATUS_BLOCK Iosb
;
891 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
892 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
893 sizeof(LPC_MESSAGE_HEADER
);
896 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.ScreenBufferInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
899 return Reply
->Status
= STATUS_INVALID_HANDLE
;
901 pInfo
= &Reply
->Data
.ScreenBufferInfoReply
.Info
;
902 if( Buff
== ActiveConsole
->ActiveBuffer
)
904 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
, 0, 0, pInfo
, sizeof( *pInfo
) );
905 if( !NT_SUCCESS( Status
) )
906 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
907 Reply
->Status
= Status
;
910 pInfo
->dwSize
.X
= PhysicalConsoleSize
.X
;
911 pInfo
->dwSize
.Y
= PhysicalConsoleSize
.Y
;
912 pInfo
->dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
913 pInfo
->dwCursorPosition
.Y
= (Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
914 pInfo
->wAttributes
= Buff
->DefaultAttrib
;
915 pInfo
->srWindow
.Left
= 0;
916 pInfo
->srWindow
.Right
= PhysicalConsoleSize
.X
- 1;
917 pInfo
->srWindow
.Top
= 0;
918 pInfo
->srWindow
.Bottom
= PhysicalConsoleSize
.Y
- 1;
919 Reply
->Status
= STATUS_SUCCESS
;
922 return Reply
->Status
;
925 NTSTATUS
CsrSetCursor( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
928 PCSRSS_SCREEN_BUFFER Buff
;
929 CONSOLE_SCREEN_BUFFER_INFO Info
;
930 IO_STATUS_BLOCK Iosb
;
932 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
933 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
934 sizeof(LPC_MESSAGE_HEADER
);
937 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.SetCursorRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
940 return Reply
->Status
= STATUS_INVALID_HANDLE
;
942 Info
.dwCursorPosition
= Request
->Data
.SetCursorRequest
.Position
;
943 Info
.wAttributes
= Buff
->DefaultAttrib
;
944 if( Buff
== ActiveConsole
->ActiveBuffer
)
946 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &Info
, sizeof( Info
), 0, 0 );
947 if( !NT_SUCCESS( Status
) )
948 DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
950 Buff
->CurrentX
= Info
.dwCursorPosition
.X
+ Buff
->ShowX
;
951 Buff
->CurrentY
= (Info
.dwCursorPosition
.Y
+ Buff
->ShowY
) % Buff
->MaxY
;
953 return Reply
->Status
= Status
;
956 NTSTATUS
CsrWriteConsoleOutputChar( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
958 BYTE
*Buffer
= Request
->Data
.WriteConsoleOutputCharRequest
.String
;
959 PCSRSS_SCREEN_BUFFER Buff
;
962 IO_STATUS_BLOCK Iosb
;
964 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
965 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
966 sizeof(LPC_MESSAGE_HEADER
);
968 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleOutputCharRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
971 return Reply
->Status
= STATUS_INVALID_HANDLE
;
975 Buff
->CurrentX
= Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.X
;
976 Buff
->CurrentY
= Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.Y
;
977 Buffer
[Request
->Data
.WriteConsoleOutputCharRequest
.Length
] = 0;
978 CsrpWriteConsole( Buff
, Buffer
, Request
->Data
.WriteConsoleOutputCharRequest
.Length
, FALSE
);
979 if( ActiveConsole
->ActiveBuffer
== Buff
)
981 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
986 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
989 &Request
->Data
.WriteConsoleOutputCharRequest
.Coord
,
990 sizeof (COORD
) + Request
->Data
.WriteConsoleOutputCharRequest
.Length
);
991 if( !NT_SUCCESS( Status
) )
992 DPRINT1( "Failed to write output chars: %x\n", Status
);
994 Reply
->Data
.WriteConsoleOutputCharReply
.EndCoord
.X
= Buff
->CurrentX
- Buff
->ShowX
;
995 Reply
->Data
.WriteConsoleOutputCharReply
.EndCoord
.Y
= (Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
999 return Reply
->Status
= STATUS_SUCCESS
;
1002 NTSTATUS
CsrFillOutputChar( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1004 PCSRSS_SCREEN_BUFFER Buff
;
1007 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1008 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1009 sizeof(LPC_MESSAGE_HEADER
);
1012 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.FillOutputRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
1015 return Reply
->Status
= STATUS_INVALID_HANDLE
;
1017 X
= Request
->Data
.FillOutputRequest
.Position
.X
+ Buff
->ShowX
;
1018 Y
= Request
->Data
.FillOutputRequest
.Position
.Y
+ Buff
->ShowY
;
1019 for( i
= 0; i
< 20000; i
++ );
1020 for( i
= 0; i
< Request
->Data
.FillOutputRequest
.Length
; i
++ )
1022 Buff
->Buffer
[ (Y
* 2 * Buff
->MaxX
) + (X
* 2) ] = Request
->Data
.FillOutputRequest
.Char
;
1023 if( ++X
== Buff
->MaxX
)
1025 if( ++Y
== Buff
->MaxY
)
1030 if( Buff
== ActiveConsole
->ActiveBuffer
)
1031 CsrDrawConsole( Buff
);
1033 return Reply
->Status
;
1036 NTSTATUS
CsrReadInputEvent( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1038 PCSRSS_CONSOLE Console
;
1040 ConsoleInput
*Input
;
1042 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1043 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1044 sizeof(LPC_MESSAGE_HEADER
);
1045 Reply
->Data
.ReadInputReply
.Event
= ProcessData
->ConsoleEvent
;
1048 Status
= CsrGetObject( ProcessData
, Request
->Data
.ReadInputRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1049 if( !NT_SUCCESS( Status
) || (Status
= Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1051 Reply
->Status
= Status
;
1055 // only get input if there is input, and we are not in line input mode, or if we are, if we have a whole line
1056 if( Console
->InputEvents
.Flink
!= &Console
->InputEvents
&&
1057 ( !Console
->Mode
& ENABLE_LINE_INPUT
|| Console
->WaitingLines
) )
1059 Input
= (ConsoleInput
*)Console
->InputEvents
.Flink
;
1060 Input
->ListEntry
.Blink
->Flink
= Input
->ListEntry
.Flink
;
1061 Input
->ListEntry
.Flink
->Blink
= Input
->ListEntry
.Blink
;
1062 Reply
->Data
.ReadInputReply
.Input
= Input
->InputEvent
;
1063 if( Console
->Mode
& ENABLE_LINE_INPUT
&&
1064 Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
&&
1065 Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' )
1066 Console
->WaitingLines
--;
1067 Console
->WaitingChars
--;
1068 RtlFreeHeap( CsrssApiHeap
, 0, Input
);
1069 Reply
->Data
.ReadInputReply
.MoreEvents
= (Console
->InputEvents
.Flink
!= &Console
->InputEvents
) ? TRUE
: FALSE
;
1070 Status
= STATUS_SUCCESS
;
1072 else Status
= STATUS_PENDING
;
1074 return Reply
->Status
= Status
;
1077 NTSTATUS
CsrWriteConsoleOutputAttrib( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1080 PCSRSS_SCREEN_BUFFER Buff
;
1083 IO_STATUS_BLOCK Iosb
;
1085 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1086 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1087 sizeof(LPC_MESSAGE_HEADER
);
1089 Status
= CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleOutputAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1090 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1092 Reply
->Status
= Status
;
1098 Buff
->CurrentX
= Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.X
+ Buff
->ShowX
;
1099 Buff
->CurrentY
= (Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.Y
+ Buff
->ShowY
) % Buff
->MaxY
;
1100 for( c
= 0; c
< Request
->Data
.WriteConsoleOutputAttribRequest
.Length
; c
++ )
1102 Buff
->Buffer
[(Buff
->CurrentY
* Buff
->MaxX
* 2) + (Buff
->CurrentX
* 2) + 1] = Request
->Data
.WriteConsoleOutputAttribRequest
.String
[c
];
1103 if( ++Buff
->CurrentX
== Buff
->MaxX
)
1106 if( ++Buff
->CurrentY
== Buff
->MaxY
)
1110 if( Buff
== ActiveConsole
->ActiveBuffer
)
1112 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
1117 IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE
,
1120 &Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
,
1121 Request
->Data
.WriteConsoleOutputAttribRequest
.Length
+
1123 if( !NT_SUCCESS( Status
) )
1124 DPRINT1( "Failed to write output attributes to console\n" );
1126 Reply
->Data
.WriteConsoleOutputAttribReply
.EndCoord
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1127 Reply
->Data
.WriteConsoleOutputAttribReply
.EndCoord
.Y
= ( Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
1131 return Reply
->Status
= STATUS_SUCCESS
;
1134 NTSTATUS
CsrFillOutputAttrib( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1137 PCSRSS_SCREEN_BUFFER Buff
;
1140 IO_STATUS_BLOCK Iosb
;
1141 OUTPUT_ATTRIBUTE Attr
;
1143 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1144 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1145 sizeof(LPC_MESSAGE_HEADER
);
1147 Status
= CsrGetObject( ProcessData
, Request
->Data
.FillOutputAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1148 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1150 Reply
->Status
= Status
;
1156 Buff
->CurrentX
= Request
->Data
.FillOutputAttribRequest
.Coord
.X
+ Buff
->ShowX
;
1157 Buff
->CurrentY
= Request
->Data
.FillOutputAttribRequest
.Coord
.Y
+ Buff
->ShowY
;
1158 for( c
= 0; c
< Request
->Data
.FillOutputAttribRequest
.Length
; c
++ )
1160 Buff
->Buffer
[(Buff
->CurrentY
* Buff
->MaxX
* 2) + (Buff
->CurrentX
* 2) + 1] = Request
->Data
.FillOutputAttribRequest
.Attribute
;
1161 if( ++Buff
->CurrentX
== Buff
->MaxX
)
1164 if( ++Buff
->CurrentY
== Buff
->MaxY
)
1168 if( Buff
== ActiveConsole
->ActiveBuffer
)
1170 Attr
.wAttribute
= Request
->Data
.FillOutputAttribRequest
.Attribute
;
1171 Attr
.nLength
= Request
->Data
.FillOutputAttribRequest
.Length
;
1172 Attr
.dwCoord
= Request
->Data
.FillOutputAttribRequest
.Coord
;
1173 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
1178 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE
,
1183 if( !NT_SUCCESS( Status
) )
1184 DPRINT1( "Failed to fill output attribute\n" );
1189 return Reply
->Status
= STATUS_SUCCESS
;
1193 NTSTATUS
CsrGetCursorInfo( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1195 PCSRSS_SCREEN_BUFFER Buff
;
1198 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1199 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1200 sizeof(LPC_MESSAGE_HEADER
);
1202 Status
= CsrGetObject( ProcessData
, Request
->Data
.GetCursorInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1203 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1205 Reply
->Status
= Status
;
1209 Reply
->Data
.GetCursorInfoReply
.Info
= Buff
->CursorInfo
;
1211 return Reply
->Status
= STATUS_SUCCESS
;
1214 NTSTATUS
CsrSetCursorInfo( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1216 PCSRSS_SCREEN_BUFFER Buff
;
1218 IO_STATUS_BLOCK Iosb
;
1220 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1221 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1222 sizeof(LPC_MESSAGE_HEADER
);
1224 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetCursorInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1225 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1227 Reply
->Status
= Status
;
1231 Buff
->CursorInfo
= Request
->Data
.SetCursorInfoRequest
.Info
;
1232 if( Buff
== ActiveConsole
->ActiveBuffer
)
1234 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_CURSOR_INFO
, &Buff
->CursorInfo
, sizeof( Buff
->CursorInfo
), 0, 0 );
1235 if( !NT_SUCCESS( Status
) )
1237 DbgPrint( "CSR: Failed to set cursor info\n" );
1238 return Reply
->Status
= Status
;
1242 return Reply
->Status
= STATUS_SUCCESS
;
1245 NTSTATUS
CsrSetTextAttrib( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1248 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
1249 IO_STATUS_BLOCK Iosb
;
1250 PCSRSS_SCREEN_BUFFER Buff
;
1252 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1253 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1254 sizeof(LPC_MESSAGE_HEADER
);
1256 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1257 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1259 Reply
->Status
= Status
;
1263 Buff
->DefaultAttrib
= Request
->Data
.SetAttribRequest
.Attrib
;
1264 if( Buff
== ActiveConsole
->ActiveBuffer
)
1266 ScrInfo
.wAttributes
= Buff
->DefaultAttrib
;
1267 ScrInfo
.dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1268 ScrInfo
.dwCursorPosition
.Y
= ((Buff
->CurrentY
+ Buff
->MaxY
) - Buff
->ShowY
) % Buff
->MaxY
;
1269 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
1270 if( !NT_SUCCESS( Status
) )
1272 DbgPrint( "CSR: Failed to set console info\n" );
1274 return Reply
->Status
= Status
;
1278 return Reply
->Status
= STATUS_SUCCESS
;
1281 NTSTATUS
CsrSetConsoleMode( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1284 PCSRSS_CONSOLE Console
;
1285 PCSRSS_SCREEN_BUFFER Buff
;
1287 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1288 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1290 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetConsoleModeRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1291 if( !NT_SUCCESS( Status
) )
1293 Reply
->Status
= Status
;
1297 Buff
= (PCSRSS_SCREEN_BUFFER
)Console
;
1298 if( Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
)
1299 Console
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_INPUT_MODE_VALID
;
1300 else if( Console
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
)
1301 Buff
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_OUTPUT_MODE_VALID
;
1303 Reply
->Status
= STATUS_INVALID_HANDLE
;
1308 Reply
->Status
= STATUS_SUCCESS
;
1309 return Reply
->Status
;
1312 NTSTATUS
CsrGetConsoleMode( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1315 PCSRSS_CONSOLE Console
;
1316 PCSRSS_SCREEN_BUFFER Buff
; /* gee, I really wish I could use an anonymous union here */
1318 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1319 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1321 Status
= CsrGetObject( ProcessData
, Request
->Data
.GetConsoleModeRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1322 if( !NT_SUCCESS( Status
) )
1324 Reply
->Status
= Status
;
1328 Reply
->Status
= STATUS_SUCCESS
;
1329 Buff
= (PCSRSS_SCREEN_BUFFER
)Console
;
1330 if( Console
->Header
.Type
= CSRSS_CONSOLE_MAGIC
)
1331 Reply
->Data
.GetConsoleModeReply
.ConsoleMode
= Console
->Mode
;
1332 else if( Buff
->Header
.Type
= CSRSS_SCREEN_BUFFER_MAGIC
)
1333 Reply
->Data
.GetConsoleModeReply
.ConsoleMode
= Buff
->Mode
;
1334 else Status
= STATUS_INVALID_HANDLE
;
1336 return Reply
->Status
;
1339 NTSTATUS
CsrCreateScreenBuffer( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1341 PCSRSS_SCREEN_BUFFER Buff
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_SCREEN_BUFFER
) );
1344 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1345 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1347 Reply
->Status
= STATUS_INSUFFICIENT_RESOURCES
;
1349 Status
= CsrInitConsoleScreenBuffer( Buff
);
1350 if( !NT_SUCCESS( Status
) )
1351 Reply
->Status
= Status
;
1353 Status
= CsrInsertObject( ProcessData
, &Reply
->Data
.CreateScreenBufferReply
.OutputHandle
, &Buff
->Header
);
1354 if( !NT_SUCCESS( Status
) )
1355 Reply
->Status
= Status
;
1356 else Reply
->Status
= STATUS_SUCCESS
;
1359 return Reply
->Status
;
1362 NTSTATUS
CsrSetScreenBuffer( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1365 PCSRSS_SCREEN_BUFFER Buff
;
1367 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1368 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1370 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetActiveScreenBufferRequest
.OutputHandle
, (Object_t
**)&Buff
);
1371 if( !NT_SUCCESS( Status
) )
1372 Reply
->Status
= Status
;
1374 // drop reference to old buffer, maybe delete
1375 if( !InterlockedDecrement( &ProcessData
->Console
->ActiveBuffer
->Header
.ReferenceCount
) )
1376 CsrDeleteScreenBuffer( ProcessData
->Console
->ActiveBuffer
);
1377 // tie console to new buffer
1378 ProcessData
->Console
->ActiveBuffer
= Buff
;
1379 // inc ref count on new buffer
1380 InterlockedIncrement( &Buff
->Header
.ReferenceCount
);
1381 // if the console is active, redraw it
1382 if( ActiveConsole
== ProcessData
->Console
)
1383 CsrDrawConsole( Buff
);
1384 Reply
->Status
= STATUS_SUCCESS
;
1387 return Reply
->Status
;
1390 NTSTATUS
CsrSetTitle( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1393 PCSRSS_CONSOLE Console
;
1395 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1396 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1398 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetTitleRequest
.Console
, (Object_t
**)&Console
);
1399 if( !NT_SUCCESS( Status
) )
1400 Reply
->Status
= Status
;
1402 // copy title to console
1403 RtlFreeUnicodeString( &Console
->Title
);
1404 RtlCreateUnicodeString( &Console
->Title
, Request
->Data
.SetTitleRequest
.Title
);
1405 Reply
->Status
= STATUS_SUCCESS
;
1408 return Reply
->Status
;