1 /* $Id: conio.c,v 1.21 2001/07/31 20:28:43 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);
229 PCSRSS_SCREEN_BUFFER Buff
,
233 DWORD Offset
= 2 * ((Buff
->CurrentY
* Buff
->MaxX
) + StartX
);
235 for ( ; StartX
< Buff
->MaxX
; StartX
++ )
237 /* Fill the cell: Offset is incremented by the macro */
238 SET_CELL_BUFFER(Buff
,Offset
,' ',Buff
->DefaultAttrib
)
242 NTSTATUS
CsrpWriteConsole( PCSRSS_SCREEN_BUFFER Buff
, CHAR
*Buffer
, DWORD Length
, BOOL Attrib
)
244 IO_STATUS_BLOCK Iosb
;
249 for( i
= 0; i
< Length
; i
++ )
251 switch( Buffer
[ i
] )
256 /* slide the viewable screen */
257 if( ((PhysicalConsoleSize
.Y
+ Buff
->ShowY
) % Buff
->MaxY
) == (Buff
->CurrentY
+ 1) % Buff
->MaxY
)
258 if( ++Buff
->ShowY
== (Buff
->MaxY
- 1) )
260 if( ++Buff
->CurrentY
== Buff
->MaxY
)
264 ClearLineBuffer (Buff
, 0);
268 if( Buff
->CurrentX
== 0 )
270 /* slide viewable screen up */
271 if( Buff
->ShowY
== Buff
->CurrentY
)
273 if( Buff
->ShowY
== 0 )
274 Buff
->ShowY
= Buff
->MaxY
;
278 /* slide virtual position up */
279 Buff
->CurrentX
= Buff
->MaxX
;
280 if( Buff
->CurrentY
== 0 )
281 Buff
->CurrentY
= Buff
->MaxY
;
287 Offset
= 2 * ((Buff
->CurrentY
* Buff
->MaxX
) + Buff
->CurrentX
);
288 SET_CELL_BUFFER(Buff
,Offset
,' ',Buff
->DefaultAttrib
);
296 CsrpWriteConsole(Buff
, " ", 8, Attrib
);
300 Offset
= 2 * (((Buff
->CurrentY
* Buff
->MaxX
)) + Buff
->CurrentX
);
301 Buff
->Buffer
[Offset
++] = Buffer
[ i
];
303 Buff
->Buffer
[Offset
] = Buff
->DefaultAttrib
;
305 if( Buff
->CurrentX
== Buff
->MaxX
)
307 /* if end of line, go to next */
309 if( ++Buff
->CurrentY
== Buff
->MaxY
)
311 /* if end of buffer, wrap back to beginning */
314 ClearLineBuffer (Buff
, 0);
318 ClearLineBuffer (Buff
, 0);
320 /* slide the viewable screen */
321 if( (Buff
->CurrentY
- Buff
->ShowY
) == PhysicalConsoleSize
.Y
)
322 if( ++Buff
->ShowY
== Buff
->MaxY
)
327 if( Buff
== ActiveConsole
->ActiveBuffer
)
328 { /* only write to screen if Console is Active, and not scrolled up */
331 Status
= NtWriteFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, Buffer
, Length
, NULL
, 0);
332 if (!NT_SUCCESS(Status
))
333 DbgPrint("CSR: Write failed\n");
336 return(STATUS_SUCCESS
);
339 NTSTATUS
CsrWriteConsole(PCSRSS_PROCESS_DATA ProcessData
,
340 PCSRSS_API_REQUEST LpcMessage
,
341 PCSRSS_API_REPLY Reply
)
343 BYTE
*Buffer
= LpcMessage
->Data
.WriteConsoleRequest
.Buffer
;
344 PCSRSS_SCREEN_BUFFER Buff
;
346 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
347 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
348 sizeof(LPC_MESSAGE_HEADER
);
351 if( !NT_SUCCESS( CsrGetObject( ProcessData
, LpcMessage
->Data
.WriteConsoleRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
354 return Reply
->Status
= STATUS_INVALID_HANDLE
;
356 CsrpWriteConsole( Buff
, Buffer
, LpcMessage
->Data
.WriteConsoleRequest
.NrCharactersToWrite
, TRUE
);
358 return Reply
->Status
= STATUS_SUCCESS
;
362 NTSTATUS
CsrInitConsoleScreenBuffer( PCSRSS_SCREEN_BUFFER Console
)
364 Console
->Header
.Type
= CSRSS_SCREEN_BUFFER_MAGIC
;
365 Console
->Header
.ReferenceCount
= 0;
366 Console
->MaxX
= PhysicalConsoleSize
.X
;
367 Console
->MaxY
= PhysicalConsoleSize
.Y
* 2;
370 Console
->CurrentX
= 0;
371 Console
->CurrentY
= 0;
372 Console
->Buffer
= RtlAllocateHeap( CsrssApiHeap
, 0, Console
->MaxX
* Console
->MaxY
* 2 );
373 if( Console
->Buffer
== 0 )
374 return STATUS_INSUFFICIENT_RESOURCES
;
375 Console
->DefaultAttrib
= 0x17;
376 /* initialize buffer to be empty with default attributes */
377 for( ; Console
->CurrentY
< Console
->MaxY
; Console
->CurrentY
++ )
379 ClearLineBuffer (Console
, 0);
381 Console
->CursorInfo
.bVisible
= TRUE
;
382 Console
->CursorInfo
.dwSize
= 5;
383 Console
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
384 Console
->CurrentX
= 0;
385 Console
->CurrentY
= 0;
386 return STATUS_SUCCESS
;
389 VOID
CsrDeleteScreenBuffer( PCSRSS_SCREEN_BUFFER Buffer
)
391 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
->Buffer
);
392 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
);
395 NTSTATUS
CsrInitConsole(PCSRSS_CONSOLE Console
)
399 Console
->Title
.MaximumLength
= Console
->Title
.Length
= 0;
400 Console
->Title
.Buffer
= 0;
402 RtlCreateUnicodeString( &Console
->Title
, L
"Command Prompt" );
404 Console
->Header
.ReferenceCount
= 0;
405 Console
->WaitingChars
= 0;
406 Console
->WaitingLines
= 0;
407 Console
->EchoCount
= 0;
408 Console
->Header
.Type
= CSRSS_CONSOLE_MAGIC
;
409 Console
->Mode
= ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
| ENABLE_PROCESSED_INPUT
| ENABLE_MOUSE_INPUT
;
410 Console
->InputEvents
.Flink
= Console
->InputEvents
.Blink
= &Console
->InputEvents
;
411 Status
= NtCreateEvent( &Console
->ActiveEvent
, STANDARD_RIGHTS_ALL
, 0, FALSE
, FALSE
);
412 if( !NT_SUCCESS( Status
) )
416 Console
->ActiveBuffer
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_SCREEN_BUFFER
) );
417 if( !Console
->ActiveBuffer
)
419 NtClose( Console
->ActiveEvent
);
420 return STATUS_INSUFFICIENT_RESOURCES
;
422 Status
= CsrInitConsoleScreenBuffer( Console
->ActiveBuffer
);
423 if( !NT_SUCCESS( Status
) )
425 NtClose( Console
->ActiveEvent
);
426 RtlFreeHeap( CsrssApiHeap
, 0, Console
->ActiveBuffer
);
429 /* add a reference count because the buffer is tied to the console */
430 Console
->ActiveBuffer
->Header
.ReferenceCount
++;
431 /* make console active, and insert into console list */
435 Console
->Prev
= ActiveConsole
;
436 Console
->Next
= ActiveConsole
->Next
;
437 ActiveConsole
->Next
->Prev
= Console
;
438 ActiveConsole
->Next
= Console
;
441 Console
->Prev
= Console
;
442 Console
->Next
= Console
;
444 ActiveConsole
= Console
;
445 /* copy buffer contents to screen */
446 CsrDrawConsole( Console
->ActiveBuffer
);
448 return STATUS_SUCCESS
;
451 /***************************************************************
452 * CsrDrawConsole blasts the console buffer onto the screen *
453 * must be called while holding the active console lock *
454 **************************************************************/
455 VOID
CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff
)
457 IO_STATUS_BLOCK Iosb
;
459 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
463 /* first set position to 0,0 */
464 ScrInfo
.dwCursorPosition
.X
= 0;
465 ScrInfo
.dwCursorPosition
.Y
= 0;
466 ScrInfo
.wAttributes
= Buff
->DefaultAttrib
;
467 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
468 if( !NT_SUCCESS( Status
) )
470 DbgPrint( "CSR: Failed to set console info\n" );
473 Mode
.dwMode
= 0; /* clear ENABLE_PROCESSED_OUTPUT mode */
474 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_MODE
, &Mode
, sizeof( Mode
), 0, 0 );
475 if( !NT_SUCCESS( Status
) )
477 DbgPrint( "CSR: Failed to set console mode\n" );
480 /* blast out buffer */
481 for( i
= 0, y
= Buff
->ShowY
; i
< PhysicalConsoleSize
.Y
; i
++ )
483 Status
= NtWriteFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, &Buff
->Buffer
[ (Buff
->ShowX
* 2) + (y
* Buff
->MaxX
* 2) ], PhysicalConsoleSize
.X
* 2, 0, 0 );
484 if( !NT_SUCCESS( Status
) )
486 DbgPrint( "CSR: Write to console failed\n" );
489 /* wrap back around the end of the buffer */
490 if( ++y
== Buff
->MaxY
)
493 Mode
.dwMode
= ENABLE_PROCESSED_OUTPUT
;
494 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_MODE
, &Mode
, sizeof( Mode
), 0, 0 );
495 if( !NT_SUCCESS( Status
) )
497 DbgPrint( "CSR: Failed to set console mode\n" );
500 ScrInfo
.dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
501 ScrInfo
.dwCursorPosition
.Y
= ((Buff
->CurrentY
+ Buff
->MaxY
) - Buff
->ShowY
) % Buff
->MaxY
;
502 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
503 if( !NT_SUCCESS( Status
) )
505 DbgPrint( "CSR: Failed to set console info\n" );
508 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_CURSOR_INFO
, &Buff
->CursorInfo
, sizeof( Buff
->CursorInfo
), 0, 0 );
509 if( !NT_SUCCESS( Status
) )
511 DbgPrint( "CSR: Failed to set cursor info\n" );
517 VOID
CsrDeleteConsole( PCSRSS_CONSOLE Console
)
520 DPRINT1( "CsrDeleteConsole\n" );
522 /* Drain input event queue */
523 while( Console
->InputEvents
.Flink
!= &Console
->InputEvents
)
525 Event
= (ConsoleInput
*)Console
->InputEvents
.Flink
;
526 Console
->InputEvents
.Flink
= Console
->InputEvents
.Flink
->Flink
;
527 Console
->InputEvents
.Flink
->Flink
->Blink
= &Console
->InputEvents
;
528 RtlFreeHeap( CsrssApiHeap
, 0, Event
);
530 /* Switch to next console */
531 if( ActiveConsole
== Console
)
533 if( Console
->Next
!= Console
)
535 ActiveConsole
= Console
->Next
;
536 Console
->Prev
->Next
= Console
->Next
;
537 Console
->Next
->Prev
= Console
->Prev
;
539 else ActiveConsole
= 0;
542 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
544 if( !--Console
->ActiveBuffer
->Header
.ReferenceCount
)
545 CsrDeleteScreenBuffer( Console
->ActiveBuffer
);
546 NtClose( Console
->ActiveEvent
);
547 RtlFreeUnicodeString( &Console
->Title
);
548 RtlFreeHeap( CsrssApiHeap
, 0, Console
);
551 VOID
CsrInitConsoleSupport(VOID
)
553 OBJECT_ATTRIBUTES ObjectAttributes
;
554 UNICODE_STRING DeviceName
;
556 IO_STATUS_BLOCK Iosb
;
557 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
559 DbgPrint("CSR: CsrInitConsoleSupport()\n");
561 RtlInitUnicodeString(&DeviceName
, L
"\\??\\BlueScreen");
562 InitializeObjectAttributes(&ObjectAttributes
,
567 Status
= NtOpenFile(&ConsoleDeviceHandle
,
572 FILE_SYNCHRONOUS_IO_ALERT
);
573 if (!NT_SUCCESS(Status
))
575 DbgPrint("CSR: Failed to open console. Expect problems.\n");
577 // DbgPrint("CSR: ConsoleDeviceHandle %x\n", ConsoleDeviceHandle);
579 RtlInitUnicodeString(&DeviceName
, L
"\\??\\Keyboard");
580 InitializeObjectAttributes(&ObjectAttributes
,
585 Status
= NtOpenFile(&KeyboardDeviceHandle
,
591 if (!NT_SUCCESS(Status
))
593 DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
597 RtlInitializeCriticalSection( &ActiveConsoleLock
);
598 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
, 0, 0, &ScrInfo
, sizeof( ScrInfo
) );
599 if( !NT_SUCCESS( Status
) )
601 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
604 PhysicalConsoleSize
= ScrInfo
.dwSize
;
607 VOID
Console_Api( DWORD RefreshEvent
)
609 /* keep reading events from the keyboard and stuffing them into the current
610 console's input queue */
611 ConsoleInput
*KeyEventRecord
;
612 ConsoleInput
*TempInput
;
613 IO_STATUS_BLOCK Iosb
;
615 HANDLE Events
[2]; // 0 = keyboard, 1 = refresh
618 PCSRSS_CONSOLE SwapConsole
= 0; // console we are thinking about swapping with
621 Status
= NtCreateEvent( &Events
[0], STANDARD_RIGHTS_ALL
, NULL
, FALSE
, FALSE
);
622 if( !NT_SUCCESS( Status
) )
624 DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status
);
625 NtTerminateProcess( NtCurrentProcess(), Status
);
627 Events
[1] = (HANDLE
)RefreshEvent
;
630 KeyEventRecord
= RtlAllocateHeap(CsrssApiHeap
,
632 sizeof(ConsoleInput
));
633 if ( KeyEventRecord
== 0 )
635 DbgPrint( "CSR: Memory allocation failure!" );
638 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
639 Status
= NtReadFile( KeyboardDeviceHandle
, Events
[0], NULL
, NULL
, &Iosb
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
, sizeof( KEY_EVENT_RECORD
), NULL
, 0 );
640 if( !NT_SUCCESS( Status
) )
642 DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
643 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
646 if( Status
== STATUS_PENDING
)
650 Status
= NtWaitForMultipleObjects( 2, Events
, WaitAny
, FALSE
, NULL
);
651 if( Status
== STATUS_WAIT_0
+ 1 )
654 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
658 else if( Status
!= STATUS_WAIT_0
)
660 DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status
);
661 NtTerminateProcess( NtCurrentProcess(), Status
);
666 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
& ( RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
)&& KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_TAB
)
667 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
)
672 unsigned int src
, dst
;
674 /* alt-tab, swap consoles */
675 // move SwapConsole to next console, and print its title
678 SwapConsole
= ActiveConsole
;
680 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
)
681 SwapConsole
= SwapConsole
->Prev
;
682 else SwapConsole
= SwapConsole
->Next
;
683 Title
.MaximumLength
= RtlUnicodeStringToAnsiSize( &SwapConsole
->Title
);
685 Buffer
= RtlAllocateHeap( CsrssApiHeap
,
687 sizeof( COORD
) + Title
.MaximumLength
);
688 pos
= (COORD
*)Buffer
;
689 Title
.Buffer
= Buffer
+ sizeof( COORD
);
691 /* this does not seem to work
692 RtlUnicodeStringToAnsiString( &Title, &SwapConsole->Title, FALSE ); */
694 for( src
= 0, dst
= 0; src
< SwapConsole
->Title
.Length
; src
++, dst
++ )
695 Title
.Buffer
[dst
] = (char)SwapConsole
->Title
.Buffer
[dst
];
697 pos
->Y
= PhysicalConsoleSize
.Y
/ 2;
698 pos
->X
= ( PhysicalConsoleSize
.X
- Title
.MaximumLength
) / 2;
699 // redraw the console to clear off old title
700 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
701 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
706 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
710 sizeof (COORD
) + Title
.MaximumLength
);
711 if( !NT_SUCCESS( Status
) )
713 DPRINT1( "Error writing to console\n" );
715 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
);
718 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
722 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
725 else if( SwapConsole
&&
726 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_MENU
&&
727 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
)
729 // alt key released, swap consoles
733 if( SwapConsole
!= ActiveConsole
)
735 // first remove swapconsole from the list
736 SwapConsole
->Prev
->Next
= SwapConsole
->Next
;
737 SwapConsole
->Next
->Prev
= SwapConsole
->Prev
;
738 // now insert before activeconsole
739 SwapConsole
->Next
= ActiveConsole
;
740 SwapConsole
->Prev
= ActiveConsole
->Prev
;
741 ActiveConsole
->Prev
->Next
= SwapConsole
;
742 ActiveConsole
->Prev
= SwapConsole
;
744 ActiveConsole
= SwapConsole
;
746 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
750 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
) )
752 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
)
754 /* scroll up or down */
756 if( ActiveConsole
== 0 )
758 DbgPrint( "CSR: No Active Console!\n" );
760 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
763 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)
765 /* only scroll up if there is room to scroll up into */
766 if( ActiveConsole
->ActiveBuffer
->ShowY
!= ((ActiveConsole
->ActiveBuffer
->CurrentY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
) )
767 ActiveConsole
->ActiveBuffer
->ShowY
= (ActiveConsole
->ActiveBuffer
->ShowY
+ ActiveConsole
->ActiveBuffer
->MaxY
- 1) % ActiveConsole
->ActiveBuffer
->MaxY
;
769 else if( ActiveConsole
->ActiveBuffer
->ShowY
!= ActiveConsole
->ActiveBuffer
->CurrentY
)
770 /* only scroll down if there is room to scroll down into */
771 if( ActiveConsole
->ActiveBuffer
->ShowY
% ActiveConsole
->ActiveBuffer
->MaxY
!= ActiveConsole
->ActiveBuffer
->CurrentY
)
772 if( ((ActiveConsole
->ActiveBuffer
->CurrentY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
) != (ActiveConsole
->ActiveBuffer
->ShowY
+ PhysicalConsoleSize
.Y
) % ActiveConsole
->ActiveBuffer
->MaxY
)
773 ActiveConsole
->ActiveBuffer
->ShowY
= (ActiveConsole
->ActiveBuffer
->ShowY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
;
774 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
777 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
781 if( ActiveConsole
== 0 )
783 DbgPrint( "CSR: No Active Console!\n" );
785 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
788 // process special keys if enabled
789 if( ActiveConsole
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
) )
790 switch( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
793 // add a \n to the queue as well
795 updown
= KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
;
796 KeyEventRecord
->Echoed
= FALSE
;
797 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\r';
798 KeyEventRecord
->ListEntry
.Flink
= &ActiveConsole
->InputEvents
;
799 KeyEventRecord
->ListEntry
.Blink
= ActiveConsole
->InputEvents
.Blink
;
800 ActiveConsole
->InputEvents
.Blink
->Flink
= &KeyEventRecord
->ListEntry
;
801 ActiveConsole
->InputEvents
.Blink
= &KeyEventRecord
->ListEntry
;
802 ActiveConsole
->WaitingChars
++;
803 KeyEventRecord
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( ConsoleInput
) );
804 if( !KeyEventRecord
)
806 DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
810 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
811 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
= updown
;
812 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
= 0;
813 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualScanCode
= 0;
814 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\n';
816 // add event to the queue
817 KeyEventRecord
->ListEntry
.Flink
= &ActiveConsole
->InputEvents
;
818 KeyEventRecord
->ListEntry
.Blink
= ActiveConsole
->InputEvents
.Blink
;
819 ActiveConsole
->InputEvents
.Blink
->Flink
= &KeyEventRecord
->ListEntry
;
820 ActiveConsole
->InputEvents
.Blink
= &KeyEventRecord
->ListEntry
;
821 // if line input mode is enabled, only wake the client on enter key down
822 if( !(ActiveConsole
->Mode
& ENABLE_LINE_INPUT
) ||
823 ( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' &&
824 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
) )
826 NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
827 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' )
828 ActiveConsole
->WaitingLines
++;
830 KeyEventRecord
->Echoed
= FALSE
;
831 if( ActiveConsole
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
) &&
832 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\b' &&
833 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
)
835 // walk the input queue looking for a char to backspace
836 for( TempInput
= (ConsoleInput
*)ActiveConsole
->InputEvents
.Blink
;
837 TempInput
!= (ConsoleInput
*)&ActiveConsole
->InputEvents
&&
838 (TempInput
->InputEvent
.EventType
!= KEY_EVENT
||
839 TempInput
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
||
840 TempInput
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\b' );
841 TempInput
= (ConsoleInput
*)TempInput
->ListEntry
.Blink
);
842 // if we found one, delete it, otherwise, wake the client
843 if( TempInput
!= (ConsoleInput
*)&ActiveConsole
->InputEvents
)
845 // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
846 TempInput
->ListEntry
.Blink
->Flink
= TempInput
->ListEntry
.Flink
;
847 TempInput
->ListEntry
.Flink
->Blink
= TempInput
->ListEntry
.Blink
;
848 if( TempInput
->Echoed
)
849 CsrpWriteConsole( ActiveConsole
->ActiveBuffer
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
850 RtlFreeHeap( CsrssApiHeap
, 0, TempInput
);
851 KeyEventRecord
->ListEntry
.Blink
->Flink
= KeyEventRecord
->ListEntry
.Flink
;
852 KeyEventRecord
->ListEntry
.Flink
->Blink
= KeyEventRecord
->ListEntry
.Blink
;
853 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
854 ActiveConsole
->WaitingChars
-= 2;
856 else NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
859 // echo chars if we are supposed to and client is waiting for some
860 if( ActiveConsole
->Mode
& ENABLE_ECHO_INPUT
&& ActiveConsole
->EchoCount
&&
861 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
&&
862 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
&&
863 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
!= '\r' )
865 // mark the char as already echoed
866 CsrpWriteConsole( ActiveConsole
->ActiveBuffer
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
867 ActiveConsole
->EchoCount
--;
868 KeyEventRecord
->Echoed
= TRUE
;
871 ActiveConsole
->WaitingChars
++;
872 if( !(ActiveConsole
->Mode
& ENABLE_LINE_INPUT
) )
873 NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
878 NTSTATUS
CsrGetScreenBufferInfo( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
881 PCSRSS_SCREEN_BUFFER Buff
;
882 PCONSOLE_SCREEN_BUFFER_INFO pInfo
;
883 IO_STATUS_BLOCK Iosb
;
885 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
886 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
887 sizeof(LPC_MESSAGE_HEADER
);
890 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.ScreenBufferInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
893 return Reply
->Status
= STATUS_INVALID_HANDLE
;
895 pInfo
= &Reply
->Data
.ScreenBufferInfoReply
.Info
;
896 if( Buff
== ActiveConsole
->ActiveBuffer
)
898 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
, 0, 0, pInfo
, sizeof( *pInfo
) );
899 if( !NT_SUCCESS( Status
) )
900 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
901 Reply
->Status
= Status
;
904 pInfo
->dwSize
.X
= PhysicalConsoleSize
.X
;
905 pInfo
->dwSize
.Y
= PhysicalConsoleSize
.Y
;
906 pInfo
->dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
907 pInfo
->dwCursorPosition
.Y
= (Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
908 pInfo
->wAttributes
= Buff
->DefaultAttrib
;
909 pInfo
->srWindow
.Left
= 0;
910 pInfo
->srWindow
.Right
= PhysicalConsoleSize
.X
- 1;
911 pInfo
->srWindow
.Top
= 0;
912 pInfo
->srWindow
.Bottom
= PhysicalConsoleSize
.Y
- 1;
913 Reply
->Status
= STATUS_SUCCESS
;
916 return Reply
->Status
;
919 NTSTATUS
CsrSetCursor( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
922 PCSRSS_SCREEN_BUFFER Buff
;
923 CONSOLE_SCREEN_BUFFER_INFO Info
;
924 IO_STATUS_BLOCK Iosb
;
926 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
927 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
928 sizeof(LPC_MESSAGE_HEADER
);
931 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.SetCursorRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
934 return Reply
->Status
= STATUS_INVALID_HANDLE
;
936 Info
.dwCursorPosition
= Request
->Data
.SetCursorRequest
.Position
;
937 Info
.wAttributes
= Buff
->DefaultAttrib
;
938 if( Buff
== ActiveConsole
->ActiveBuffer
)
940 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &Info
, sizeof( Info
), 0, 0 );
941 if( !NT_SUCCESS( Status
) )
942 DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
944 Buff
->CurrentX
= Info
.dwCursorPosition
.X
+ Buff
->ShowX
;
945 Buff
->CurrentY
= (Info
.dwCursorPosition
.Y
+ Buff
->ShowY
) % Buff
->MaxY
;
947 return Reply
->Status
= Status
;
950 NTSTATUS
CsrWriteConsoleOutputChar( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
952 BYTE
*Buffer
= Request
->Data
.WriteConsoleOutputCharRequest
.String
;
953 PCSRSS_SCREEN_BUFFER Buff
;
956 IO_STATUS_BLOCK Iosb
;
958 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
959 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
960 sizeof(LPC_MESSAGE_HEADER
);
962 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleOutputCharRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
965 return Reply
->Status
= STATUS_INVALID_HANDLE
;
969 Buff
->CurrentX
= Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.X
;
970 Buff
->CurrentY
= Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.Y
;
971 Buffer
[Request
->Data
.WriteConsoleOutputCharRequest
.Length
] = 0;
972 CsrpWriteConsole( Buff
, Buffer
, Request
->Data
.WriteConsoleOutputCharRequest
.Length
, FALSE
);
973 if( ActiveConsole
->ActiveBuffer
== Buff
)
975 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
980 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
983 &Request
->Data
.WriteConsoleOutputCharRequest
.Coord
,
984 sizeof (COORD
) + Request
->Data
.WriteConsoleOutputCharRequest
.Length
);
985 if( !NT_SUCCESS( Status
) )
986 DPRINT1( "Failed to write output chars: %x\n", Status
);
988 Reply
->Data
.WriteConsoleOutputCharReply
.EndCoord
.X
= Buff
->CurrentX
- Buff
->ShowX
;
989 Reply
->Data
.WriteConsoleOutputCharReply
.EndCoord
.Y
= (Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
993 return Reply
->Status
= STATUS_SUCCESS
;
996 NTSTATUS
CsrFillOutputChar( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
998 PCSRSS_SCREEN_BUFFER Buff
;
1001 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1002 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1003 sizeof(LPC_MESSAGE_HEADER
);
1006 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.FillOutputRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
1009 return Reply
->Status
= STATUS_INVALID_HANDLE
;
1011 X
= Request
->Data
.FillOutputRequest
.Position
.X
+ Buff
->ShowX
;
1012 Y
= Request
->Data
.FillOutputRequest
.Position
.Y
+ Buff
->ShowY
;
1013 for( i
= 0; i
< 20000; i
++ );
1014 for( i
= 0; i
< Request
->Data
.FillOutputRequest
.Length
; i
++ )
1016 Buff
->Buffer
[ (Y
* 2 * Buff
->MaxX
) + (X
* 2) ] = Request
->Data
.FillOutputRequest
.Char
;
1017 if( ++X
== Buff
->MaxX
)
1019 if( ++Y
== Buff
->MaxY
)
1024 if( Buff
== ActiveConsole
->ActiveBuffer
)
1025 CsrDrawConsole( Buff
);
1027 return Reply
->Status
;
1030 NTSTATUS
CsrReadInputEvent( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1032 PCSRSS_CONSOLE Console
;
1034 ConsoleInput
*Input
;
1036 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1037 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1038 sizeof(LPC_MESSAGE_HEADER
);
1039 Reply
->Data
.ReadInputReply
.Event
= ProcessData
->ConsoleEvent
;
1042 Status
= CsrGetObject( ProcessData
, Request
->Data
.ReadInputRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1043 if( !NT_SUCCESS( Status
) || (Status
= Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1045 Reply
->Status
= Status
;
1049 // 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
1050 if( Console
->InputEvents
.Flink
!= &Console
->InputEvents
&&
1051 ( !Console
->Mode
& ENABLE_LINE_INPUT
|| Console
->WaitingLines
) )
1053 Input
= (ConsoleInput
*)Console
->InputEvents
.Flink
;
1054 Input
->ListEntry
.Blink
->Flink
= Input
->ListEntry
.Flink
;
1055 Input
->ListEntry
.Flink
->Blink
= Input
->ListEntry
.Blink
;
1056 Reply
->Data
.ReadInputReply
.Input
= Input
->InputEvent
;
1057 if( Console
->Mode
& ENABLE_LINE_INPUT
&&
1058 Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
&&
1059 Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' )
1060 Console
->WaitingLines
--;
1061 Console
->WaitingChars
--;
1062 RtlFreeHeap( CsrssApiHeap
, 0, Input
);
1063 Reply
->Data
.ReadInputReply
.MoreEvents
= (Console
->InputEvents
.Flink
!= &Console
->InputEvents
) ? TRUE
: FALSE
;
1064 Status
= STATUS_SUCCESS
;
1066 else Status
= STATUS_PENDING
;
1068 return Reply
->Status
= Status
;
1071 NTSTATUS
CsrWriteConsoleOutputAttrib( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1074 PCSRSS_SCREEN_BUFFER Buff
;
1077 IO_STATUS_BLOCK Iosb
;
1079 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1080 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1081 sizeof(LPC_MESSAGE_HEADER
);
1083 Status
= CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleOutputAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1084 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1086 Reply
->Status
= Status
;
1092 Buff
->CurrentX
= Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.X
+ Buff
->ShowX
;
1093 Buff
->CurrentY
= (Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.Y
+ Buff
->ShowY
) % Buff
->MaxY
;
1094 for( c
= 0; c
< Request
->Data
.WriteConsoleOutputAttribRequest
.Length
; c
++ )
1096 Buff
->Buffer
[(Buff
->CurrentY
* Buff
->MaxX
* 2) + (Buff
->CurrentX
* 2) + 1] = Request
->Data
.WriteConsoleOutputAttribRequest
.String
[c
];
1097 if( ++Buff
->CurrentX
== Buff
->MaxX
)
1100 if( ++Buff
->CurrentY
== Buff
->MaxY
)
1104 if( Buff
== ActiveConsole
->ActiveBuffer
)
1106 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
1111 IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE
,
1114 &Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
,
1115 Request
->Data
.WriteConsoleOutputAttribRequest
.Length
+
1117 if( !NT_SUCCESS( Status
) )
1118 DPRINT1( "Failed to write output attributes to console\n" );
1120 Reply
->Data
.WriteConsoleOutputAttribReply
.EndCoord
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1121 Reply
->Data
.WriteConsoleOutputAttribReply
.EndCoord
.Y
= ( Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
1125 return Reply
->Status
= STATUS_SUCCESS
;
1128 NTSTATUS
CsrFillOutputAttrib( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1131 PCSRSS_SCREEN_BUFFER Buff
;
1134 IO_STATUS_BLOCK Iosb
;
1135 OUTPUT_ATTRIBUTE Attr
;
1137 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1138 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1139 sizeof(LPC_MESSAGE_HEADER
);
1141 Status
= CsrGetObject( ProcessData
, Request
->Data
.FillOutputAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1142 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1144 Reply
->Status
= Status
;
1150 Buff
->CurrentX
= Request
->Data
.FillOutputAttribRequest
.Coord
.X
+ Buff
->ShowX
;
1151 Buff
->CurrentY
= Request
->Data
.FillOutputAttribRequest
.Coord
.Y
+ Buff
->ShowY
;
1152 for( c
= 0; c
< Request
->Data
.FillOutputAttribRequest
.Length
; c
++ )
1154 Buff
->Buffer
[(Buff
->CurrentY
* Buff
->MaxX
* 2) + (Buff
->CurrentX
* 2) + 1] = Request
->Data
.FillOutputAttribRequest
.Attribute
;
1155 if( ++Buff
->CurrentX
== Buff
->MaxX
)
1158 if( ++Buff
->CurrentY
== Buff
->MaxY
)
1162 if( Buff
== ActiveConsole
->ActiveBuffer
)
1164 Attr
.wAttribute
= Request
->Data
.FillOutputAttribRequest
.Attribute
;
1165 Attr
.nLength
= Request
->Data
.FillOutputAttribRequest
.Length
;
1166 Attr
.dwCoord
= Request
->Data
.FillOutputAttribRequest
.Coord
;
1167 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
1172 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE
,
1177 if( !NT_SUCCESS( Status
) )
1178 DPRINT1( "Failed to fill output attribute\n" );
1183 return Reply
->Status
= STATUS_SUCCESS
;
1187 NTSTATUS
CsrGetCursorInfo( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1189 PCSRSS_SCREEN_BUFFER Buff
;
1192 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1193 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1194 sizeof(LPC_MESSAGE_HEADER
);
1196 Status
= CsrGetObject( ProcessData
, Request
->Data
.GetCursorInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1197 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1199 Reply
->Status
= Status
;
1203 Reply
->Data
.GetCursorInfoReply
.Info
= Buff
->CursorInfo
;
1205 return Reply
->Status
= STATUS_SUCCESS
;
1208 NTSTATUS
CsrSetCursorInfo( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1210 PCSRSS_SCREEN_BUFFER Buff
;
1212 IO_STATUS_BLOCK Iosb
;
1214 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1215 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1216 sizeof(LPC_MESSAGE_HEADER
);
1218 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetCursorInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1219 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1221 Reply
->Status
= Status
;
1225 Buff
->CursorInfo
= Request
->Data
.SetCursorInfoRequest
.Info
;
1226 if( Buff
== ActiveConsole
->ActiveBuffer
)
1228 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_CURSOR_INFO
, &Buff
->CursorInfo
, sizeof( Buff
->CursorInfo
), 0, 0 );
1229 if( !NT_SUCCESS( Status
) )
1231 DbgPrint( "CSR: Failed to set cursor info\n" );
1232 return Reply
->Status
= Status
;
1236 return Reply
->Status
= STATUS_SUCCESS
;
1239 NTSTATUS
CsrSetTextAttrib( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1242 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
1243 IO_STATUS_BLOCK Iosb
;
1244 PCSRSS_SCREEN_BUFFER Buff
;
1246 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1247 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1248 sizeof(LPC_MESSAGE_HEADER
);
1250 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1251 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1253 Reply
->Status
= Status
;
1257 Buff
->DefaultAttrib
= Request
->Data
.SetAttribRequest
.Attrib
;
1258 if( Buff
== ActiveConsole
->ActiveBuffer
)
1260 ScrInfo
.wAttributes
= Buff
->DefaultAttrib
;
1261 ScrInfo
.dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1262 ScrInfo
.dwCursorPosition
.Y
= ((Buff
->CurrentY
+ Buff
->MaxY
) - Buff
->ShowY
) % Buff
->MaxY
;
1263 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
1264 if( !NT_SUCCESS( Status
) )
1266 DbgPrint( "CSR: Failed to set console info\n" );
1268 return Reply
->Status
= Status
;
1272 return Reply
->Status
= STATUS_SUCCESS
;
1275 NTSTATUS
CsrSetConsoleMode( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1278 PCSRSS_CONSOLE Console
;
1279 PCSRSS_SCREEN_BUFFER Buff
;
1281 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1282 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1284 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetConsoleModeRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1285 if( !NT_SUCCESS( Status
) )
1287 Reply
->Status
= Status
;
1291 Buff
= (PCSRSS_SCREEN_BUFFER
)Console
;
1292 if( Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
)
1293 Console
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_INPUT_MODE_VALID
;
1294 else if( Console
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
)
1295 Buff
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_OUTPUT_MODE_VALID
;
1297 Reply
->Status
= STATUS_INVALID_HANDLE
;
1302 Reply
->Status
= STATUS_SUCCESS
;
1303 return Reply
->Status
;
1306 NTSTATUS
CsrGetConsoleMode( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1309 PCSRSS_CONSOLE Console
;
1310 PCSRSS_SCREEN_BUFFER Buff
; /* gee, I really wish I could use an anonymous union here */
1312 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1313 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1315 Status
= CsrGetObject( ProcessData
, Request
->Data
.GetConsoleModeRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1316 if( !NT_SUCCESS( Status
) )
1318 Reply
->Status
= Status
;
1322 Reply
->Status
= STATUS_SUCCESS
;
1323 Buff
= (PCSRSS_SCREEN_BUFFER
)Console
;
1324 if( Console
->Header
.Type
= CSRSS_CONSOLE_MAGIC
)
1325 Reply
->Data
.GetConsoleModeReply
.ConsoleMode
= Console
->Mode
;
1326 else if( Buff
->Header
.Type
= CSRSS_SCREEN_BUFFER_MAGIC
)
1327 Reply
->Data
.GetConsoleModeReply
.ConsoleMode
= Buff
->Mode
;
1328 else Status
= STATUS_INVALID_HANDLE
;
1330 return Reply
->Status
;
1333 NTSTATUS
CsrCreateScreenBuffer( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1335 PCSRSS_SCREEN_BUFFER Buff
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_SCREEN_BUFFER
) );
1338 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1339 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1341 Reply
->Status
= STATUS_INSUFFICIENT_RESOURCES
;
1343 Status
= CsrInitConsoleScreenBuffer( Buff
);
1344 if( !NT_SUCCESS( Status
) )
1345 Reply
->Status
= Status
;
1347 Status
= CsrInsertObject( ProcessData
, &Reply
->Data
.CreateScreenBufferReply
.OutputHandle
, &Buff
->Header
);
1348 if( !NT_SUCCESS( Status
) )
1349 Reply
->Status
= Status
;
1350 else Reply
->Status
= STATUS_SUCCESS
;
1353 return Reply
->Status
;
1356 NTSTATUS
CsrSetScreenBuffer( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1359 PCSRSS_SCREEN_BUFFER Buff
;
1361 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1362 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1364 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetActiveScreenBufferRequest
.OutputHandle
, (Object_t
**)&Buff
);
1365 if( !NT_SUCCESS( Status
) )
1366 Reply
->Status
= Status
;
1368 // drop reference to old buffer, maybe delete
1369 if( !InterlockedDecrement( &ProcessData
->Console
->ActiveBuffer
->Header
.ReferenceCount
) )
1370 CsrDeleteScreenBuffer( ProcessData
->Console
->ActiveBuffer
);
1371 // tie console to new buffer
1372 ProcessData
->Console
->ActiveBuffer
= Buff
;
1373 // inc ref count on new buffer
1374 InterlockedIncrement( &Buff
->Header
.ReferenceCount
);
1375 // if the console is active, redraw it
1376 if( ActiveConsole
== ProcessData
->Console
)
1377 CsrDrawConsole( Buff
);
1378 Reply
->Status
= STATUS_SUCCESS
;
1381 return Reply
->Status
;
1384 NTSTATUS
CsrSetTitle( PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_API_REQUEST Request
, PCSRSS_API_REPLY Reply
)
1387 PCSRSS_CONSOLE Console
;
1389 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1390 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1392 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetTitleRequest
.Console
, (Object_t
**)&Console
);
1393 if( !NT_SUCCESS( Status
) )
1394 Reply
->Status
= Status
;
1396 // copy title to console
1397 RtlFreeUnicodeString( &Console
->Title
);
1398 RtlCreateUnicodeString( &Console
->Title
, Request
->Data
.SetTitleRequest
.Title
);
1399 Reply
->Status
= STATUS_SUCCESS
;
1402 return Reply
->Status
;