1 /* $Id: conio.c,v 1.24 2001/08/14 22:00:21 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)
24 /* GLOBALS *******************************************************************/
26 static HANDLE ConsoleDeviceHandle
;
27 static HANDLE KeyboardDeviceHandle
;
28 static PCSRSS_CONSOLE ActiveConsole
;
29 CRITICAL_SECTION ActiveConsoleLock
;
30 static COORD PhysicalConsoleSize
;
32 /* FUNCTIONS *****************************************************************/
34 CSR_API(CsrAllocConsole
)
36 PCSRSS_CONSOLE Console
;
41 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
42 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
43 sizeof(LPC_MESSAGE_HEADER
);
44 if( ProcessData
->Console
)
46 Reply
->Status
= STATUS_INVALID_PARAMETER
;
47 return STATUS_INVALID_PARAMETER
;
49 Reply
->Status
= STATUS_SUCCESS
;
50 Console
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_CONSOLE
) );
53 Reply
->Status
= STATUS_INSUFFICIENT_RESOURCES
;
54 return STATUS_INSUFFICIENT_RESOURCES
;
56 Reply
->Status
= CsrInitConsole( Console
);
57 if( !NT_SUCCESS( Reply
->Status
) )
59 RtlFreeHeap( CsrssApiHeap
, 0, Console
);
62 ProcessData
->Console
= Console
;
63 /* add a reference count because the process is tied to the console */
64 Console
->Header
.ReferenceCount
++;
65 Status
= CsrInsertObject( ProcessData
, &Reply
->Data
.AllocConsoleReply
.InputHandle
, &Console
->Header
);
66 if( !NT_SUCCESS( Status
) )
68 CsrDeleteConsole( Console
);
69 ProcessData
->Console
= 0;
70 return Reply
->Status
= Status
;
72 Status
= CsrInsertObject( ProcessData
, &Reply
->Data
.AllocConsoleReply
.OutputHandle
, &Console
->ActiveBuffer
->Header
);
73 if( !NT_SUCCESS( Status
) )
75 Console
->Header
.ReferenceCount
--;
76 CsrReleaseObject( ProcessData
, Reply
->Data
.AllocConsoleReply
.InputHandle
);
77 ProcessData
->Console
= 0;
78 return Reply
->Status
= Status
;
80 ClientId
.UniqueProcess
= (HANDLE
)ProcessData
->ProcessId
;
81 Status
= NtOpenProcess( &Process
, PROCESS_DUP_HANDLE
, 0, &ClientId
);
82 if( !NT_SUCCESS( Status
) )
84 DbgPrint( "CSR: NtOpenProcess() failed for handle duplication\n" );
85 Console
->Header
.ReferenceCount
--;
86 ProcessData
->Console
= 0;
87 CsrReleaseObject( ProcessData
, Reply
->Data
.AllocConsoleReply
.OutputHandle
);
88 CsrReleaseObject( ProcessData
, Reply
->Data
.AllocConsoleReply
.InputHandle
);
89 Reply
->Status
= Status
;
92 Status
= NtDuplicateObject( NtCurrentProcess(), &ProcessData
->Console
->ActiveEvent
, Process
, &ProcessData
->ConsoleEvent
, SYNCHRONIZE
, FALSE
, 0 );
93 if( !NT_SUCCESS( Status
) )
95 DbgPrint( "CSR: NtDuplicateObject() failed: %x\n", Status
);
97 Console
->Header
.ReferenceCount
--;
98 CsrReleaseObject( ProcessData
, Reply
->Data
.AllocConsoleReply
.OutputHandle
);
99 CsrReleaseObject( ProcessData
, Reply
->Data
.AllocConsoleReply
.InputHandle
);
100 ProcessData
->Console
= 0;
101 Reply
->Status
= Status
;
105 return STATUS_SUCCESS
;
108 CSR_API(CsrFreeConsole
)
110 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
111 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
112 sizeof(LPC_MESSAGE_HEADER
);
114 Reply
->Status
= STATUS_NOT_IMPLEMENTED
;
116 return(STATUS_NOT_IMPLEMENTED
);
119 CSR_API(CsrReadConsole
)
124 ULONG nNumberOfCharsToRead
;
125 PCSRSS_CONSOLE Console
;
128 /* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
129 nNumberOfCharsToRead
= Request
->Data
.ReadConsoleRequest
.NrCharactersToRead
> CSRSS_MAX_READ_CONSOLE_REQUEST
? CSRSS_MAX_READ_CONSOLE_REQUEST
: Request
->Data
.ReadConsoleRequest
.NrCharactersToRead
;
130 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
131 Reply
->Header
.DataSize
= Reply
->Header
.MessageSize
-
132 sizeof(LPC_MESSAGE_HEADER
);
133 Buffer
= Reply
->Data
.ReadConsoleReply
.Buffer
;
134 Reply
->Data
.ReadConsoleReply
.EventHandle
= ProcessData
->ConsoleEvent
;
136 Status
= CsrGetObject( ProcessData
, Request
->Data
.ReadConsoleRequest
.ConsoleHandle
, (Object_t
**)&Console
);
137 if( !NT_SUCCESS( Status
) )
139 Reply
->Status
= Status
;
143 if( Console
->Header
.Type
!= CSRSS_CONSOLE_MAGIC
)
145 Reply
->Status
= STATUS_INVALID_HANDLE
;
147 return STATUS_INVALID_HANDLE
;
149 for (; i
<nNumberOfCharsToRead
&& Console
->InputEvents
.Flink
!= &Console
->InputEvents
; i
++ )
151 // remove input event from queue
152 Input
= (ConsoleInput
*)Console
->InputEvents
.Flink
;
154 Input
->ListEntry
.Blink
->Flink
= Input
->ListEntry
.Flink
;
155 Input
->ListEntry
.Flink
->Blink
= Input
->ListEntry
.Blink
;
156 // only pay attention to valid ascii chars, on key down
157 if( Input
->InputEvent
.EventType
== KEY_EVENT
&&
158 Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
&&
159 Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
161 // backspace handling
162 if( Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\b' )
164 // echo if it has not already been done, and either we or the client has chars to be deleted
165 if( !Input
->Echoed
&& ( i
|| Request
->Data
.ReadConsoleRequest
.nCharsCanBeDeleted
) )
166 CsrpWriteConsole( Console
->ActiveBuffer
, &Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
168 i
-=2; // if we already have something to return, just back it up by 2
170 { // otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer
171 Reply
->Data
.ReadConsoleReply
.NrCharactersRead
= 0;
172 Reply
->Status
= STATUS_NOTIFY_CLEANUP
;
173 Console
->WaitingChars
--;
174 RtlFreeHeap( CsrssApiHeap
, 0, Input
);
176 return STATUS_NOTIFY_CLEANUP
;
178 Request
->Data
.ReadConsoleRequest
.nCharsCanBeDeleted
--;
179 Input
->Echoed
= TRUE
; // mark as echoed so we don't echo it below
181 // do not copy backspace to buffer
182 else Buffer
[i
] = Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
;
183 // echo to screen if enabled and we did not already echo the char
184 if( Console
->Mode
& ENABLE_ECHO_INPUT
&&
186 Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
!= '\r' )
187 CsrpWriteConsole( Console
->ActiveBuffer
, &Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
190 Console
->WaitingChars
--;
191 RtlFreeHeap( CsrssApiHeap
, 0, Input
);
193 Reply
->Data
.ReadConsoleReply
.NrCharactersRead
= i
;
195 Reply
->Status
= STATUS_PENDING
; // we didn't read anything
196 else if( Console
->Mode
& ENABLE_LINE_INPUT
)
197 if( !Console
->WaitingLines
|| Buffer
[i
-1] != '\n' )
199 Reply
->Status
= STATUS_PENDING
; // line buffered, didn't get a complete line
202 Console
->WaitingLines
--;
203 Reply
->Status
= STATUS_SUCCESS
; // line buffered, did get a complete line
205 else Reply
->Status
= STATUS_SUCCESS
; // not line buffered, did read something
206 if( Reply
->Status
== STATUS_PENDING
)
208 Console
->EchoCount
= nNumberOfCharsToRead
- i
;
211 Console
->EchoCount
= 0; // if the client is no longer waiting on input, do not echo
213 Reply
->Header
.MessageSize
+= i
;
215 return Reply
->Status
;
218 #define SET_CELL_BUFFER(b,o,c,a)\
219 (b)->Buffer[(o)++]=(c);\
220 (b)->Buffer[(o)++]=(a);
224 PCSRSS_SCREEN_BUFFER Buff
,
228 DWORD Offset
= 2 * ((Buff
->CurrentY
* Buff
->MaxX
) + StartX
);
230 for ( ; StartX
< Buff
->MaxX
; StartX
++ )
232 /* Fill the cell: Offset is incremented by the macro */
233 SET_CELL_BUFFER(Buff
,Offset
,' ',Buff
->DefaultAttrib
)
237 NTSTATUS STDCALL
CsrpWriteConsole( PCSRSS_SCREEN_BUFFER Buff
, CHAR
*Buffer
, DWORD Length
, BOOL Attrib
)
239 IO_STATUS_BLOCK Iosb
;
244 for( i
= 0; i
< Length
; i
++ )
246 switch( Buffer
[ i
] )
251 /* slide the viewable screen */
252 if( ((PhysicalConsoleSize
.Y
+ Buff
->ShowY
) % Buff
->MaxY
) == (Buff
->CurrentY
+ 1) % Buff
->MaxY
)
253 if( ++Buff
->ShowY
== (Buff
->MaxY
- 1) )
255 if( ++Buff
->CurrentY
== Buff
->MaxY
)
259 ClearLineBuffer (Buff
, 0);
263 if( Buff
->CurrentX
== 0 )
265 /* slide viewable screen up */
266 if( Buff
->ShowY
== Buff
->CurrentY
)
268 if( Buff
->ShowY
== 0 )
269 Buff
->ShowY
= Buff
->MaxY
;
273 /* slide virtual position up */
274 Buff
->CurrentX
= Buff
->MaxX
;
275 if( Buff
->CurrentY
== 0 )
276 Buff
->CurrentY
= Buff
->MaxY
;
282 Offset
= 2 * ((Buff
->CurrentY
* Buff
->MaxX
) + Buff
->CurrentX
);
283 SET_CELL_BUFFER(Buff
,Offset
,' ',Buff
->DefaultAttrib
);
291 CsrpWriteConsole(Buff
, " ", (8 - (Buff
->CurrentX
% 8)), FALSE
);
295 Offset
= 2 * (((Buff
->CurrentY
* Buff
->MaxX
)) + Buff
->CurrentX
);
296 Buff
->Buffer
[Offset
++] = Buffer
[ i
];
298 Buff
->Buffer
[Offset
] = Buff
->DefaultAttrib
;
300 if( Buff
->CurrentX
== Buff
->MaxX
)
302 /* if end of line, go to next */
304 if( ++Buff
->CurrentY
== Buff
->MaxY
)
306 /* if end of buffer, wrap back to beginning */
310 ClearLineBuffer (Buff
, 0);
311 /* slide the viewable screen */
312 if( (Buff
->CurrentY
- Buff
->ShowY
) == PhysicalConsoleSize
.Y
)
313 if( ++Buff
->ShowY
== Buff
->MaxY
)
318 if( Buff
== ActiveConsole
->ActiveBuffer
)
319 { /* only write to screen if Console is Active, and not scrolled up */
322 Status
= NtWriteFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, Buffer
, Length
, NULL
, 0);
323 if (!NT_SUCCESS(Status
))
324 DbgPrint("CSR: Write failed\n");
327 return(STATUS_SUCCESS
);
330 CSR_API(CsrWriteConsole
)
332 BYTE
*Buffer
= Request
->Data
.WriteConsoleRequest
.Buffer
;
333 PCSRSS_SCREEN_BUFFER Buff
;
335 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
336 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
337 sizeof(LPC_MESSAGE_HEADER
);
340 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
343 return Reply
->Status
= STATUS_INVALID_HANDLE
;
345 CsrpWriteConsole( Buff
, Buffer
, Request
->Data
.WriteConsoleRequest
.NrCharactersToWrite
, TRUE
);
347 return Reply
->Status
= STATUS_SUCCESS
;
351 NTSTATUS STDCALL
CsrInitConsoleScreenBuffer( PCSRSS_SCREEN_BUFFER Console
)
353 Console
->Header
.Type
= CSRSS_SCREEN_BUFFER_MAGIC
;
354 Console
->Header
.ReferenceCount
= 0;
355 Console
->MaxX
= PhysicalConsoleSize
.X
;
356 Console
->MaxY
= PhysicalConsoleSize
.Y
* 2;
359 Console
->CurrentX
= 0;
360 Console
->CurrentY
= 0;
361 Console
->Buffer
= RtlAllocateHeap( CsrssApiHeap
, 0, Console
->MaxX
* Console
->MaxY
* 2 );
362 if( Console
->Buffer
== 0 )
363 return STATUS_INSUFFICIENT_RESOURCES
;
364 Console
->DefaultAttrib
= 0x17;
365 /* initialize buffer to be empty with default attributes */
366 for( ; Console
->CurrentY
< Console
->MaxY
; Console
->CurrentY
++ )
368 ClearLineBuffer (Console
, 0);
370 Console
->CursorInfo
.bVisible
= TRUE
;
371 Console
->CursorInfo
.dwSize
= 5;
372 Console
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
373 Console
->CurrentX
= 0;
374 Console
->CurrentY
= 0;
375 return STATUS_SUCCESS
;
378 VOID STDCALL
CsrDeleteScreenBuffer( PCSRSS_SCREEN_BUFFER Buffer
)
380 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
->Buffer
);
381 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
);
384 NTSTATUS STDCALL
CsrInitConsole(PCSRSS_CONSOLE Console
)
388 Console
->Title
.MaximumLength
= Console
->Title
.Length
= 0;
389 Console
->Title
.Buffer
= 0;
391 RtlCreateUnicodeString( &Console
->Title
, L
"Command Prompt" );
393 Console
->Header
.ReferenceCount
= 0;
394 Console
->WaitingChars
= 0;
395 Console
->WaitingLines
= 0;
396 Console
->EchoCount
= 0;
397 Console
->Header
.Type
= CSRSS_CONSOLE_MAGIC
;
398 Console
->Mode
= ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
| ENABLE_PROCESSED_INPUT
| ENABLE_MOUSE_INPUT
;
399 Console
->InputEvents
.Flink
= Console
->InputEvents
.Blink
= &Console
->InputEvents
;
400 Status
= NtCreateEvent( &Console
->ActiveEvent
, STANDARD_RIGHTS_ALL
, 0, FALSE
, FALSE
);
401 if( !NT_SUCCESS( Status
) )
405 Console
->ActiveBuffer
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_SCREEN_BUFFER
) );
406 if( !Console
->ActiveBuffer
)
408 NtClose( Console
->ActiveEvent
);
409 return STATUS_INSUFFICIENT_RESOURCES
;
411 Status
= CsrInitConsoleScreenBuffer( Console
->ActiveBuffer
);
412 if( !NT_SUCCESS( Status
) )
414 NtClose( Console
->ActiveEvent
);
415 RtlFreeHeap( CsrssApiHeap
, 0, Console
->ActiveBuffer
);
418 /* add a reference count because the buffer is tied to the console */
419 Console
->ActiveBuffer
->Header
.ReferenceCount
++;
420 /* make console active, and insert into console list */
424 Console
->Prev
= ActiveConsole
;
425 Console
->Next
= ActiveConsole
->Next
;
426 ActiveConsole
->Next
->Prev
= Console
;
427 ActiveConsole
->Next
= Console
;
430 Console
->Prev
= Console
;
431 Console
->Next
= Console
;
433 ActiveConsole
= Console
;
434 /* copy buffer contents to screen */
435 CsrDrawConsole( Console
->ActiveBuffer
);
437 return STATUS_SUCCESS
;
440 /***************************************************************
441 * CsrDrawConsole blasts the console buffer onto the screen *
442 * must be called while holding the active console lock *
443 **************************************************************/
444 VOID STDCALL
CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff
)
446 IO_STATUS_BLOCK Iosb
;
448 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
452 /* first set position to 0,0 */
453 ScrInfo
.dwCursorPosition
.X
= 0;
454 ScrInfo
.dwCursorPosition
.Y
= 0;
455 ScrInfo
.wAttributes
= Buff
->DefaultAttrib
;
456 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
457 if( !NT_SUCCESS( Status
) )
459 DbgPrint( "CSR: Failed to set console info\n" );
462 Mode
.dwMode
= 0; /* clear ENABLE_PROCESSED_OUTPUT mode */
463 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_MODE
, &Mode
, sizeof( Mode
), 0, 0 );
464 if( !NT_SUCCESS( Status
) )
466 DbgPrint( "CSR: Failed to set console mode\n" );
469 /* blast out buffer */
470 for( i
= 0, y
= Buff
->ShowY
; i
< PhysicalConsoleSize
.Y
; i
++ )
472 Status
= NtWriteFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, &Buff
->Buffer
[ (Buff
->ShowX
* 2) + (y
* Buff
->MaxX
* 2) ], PhysicalConsoleSize
.X
* 2, 0, 0 );
473 if( !NT_SUCCESS( Status
) )
475 DbgPrint( "CSR: Write to console failed\n" );
478 /* wrap back around the end of the buffer */
479 if( ++y
== Buff
->MaxY
)
482 Mode
.dwMode
= ENABLE_PROCESSED_OUTPUT
;
483 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_MODE
, &Mode
, sizeof( Mode
), 0, 0 );
484 if( !NT_SUCCESS( Status
) )
486 DbgPrint( "CSR: Failed to set console mode\n" );
489 ScrInfo
.dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
490 ScrInfo
.dwCursorPosition
.Y
= ((Buff
->CurrentY
+ Buff
->MaxY
) - Buff
->ShowY
) % Buff
->MaxY
;
491 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
492 if( !NT_SUCCESS( Status
) )
494 DbgPrint( "CSR: Failed to set console info\n" );
497 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_CURSOR_INFO
, &Buff
->CursorInfo
, sizeof( Buff
->CursorInfo
), 0, 0 );
498 if( !NT_SUCCESS( Status
) )
500 DbgPrint( "CSR: Failed to set cursor info\n" );
506 VOID STDCALL
CsrDeleteConsole( PCSRSS_CONSOLE Console
)
509 DPRINT1( "CsrDeleteConsole\n" );
511 /* Drain input event queue */
512 while( Console
->InputEvents
.Flink
!= &Console
->InputEvents
)
514 Event
= (ConsoleInput
*)Console
->InputEvents
.Flink
;
515 Console
->InputEvents
.Flink
= Console
->InputEvents
.Flink
->Flink
;
516 Console
->InputEvents
.Flink
->Flink
->Blink
= &Console
->InputEvents
;
517 RtlFreeHeap( CsrssApiHeap
, 0, Event
);
519 /* Switch to next console */
520 if( ActiveConsole
== Console
)
522 if( Console
->Next
!= Console
)
524 ActiveConsole
= Console
->Next
;
525 Console
->Prev
->Next
= Console
->Next
;
526 Console
->Next
->Prev
= Console
->Prev
;
528 else ActiveConsole
= 0;
531 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
533 if( !--Console
->ActiveBuffer
->Header
.ReferenceCount
)
534 CsrDeleteScreenBuffer( Console
->ActiveBuffer
);
535 NtClose( Console
->ActiveEvent
);
536 RtlFreeUnicodeString( &Console
->Title
);
537 RtlFreeHeap( CsrssApiHeap
, 0, Console
);
540 VOID STDCALL
CsrInitConsoleSupport(VOID
)
542 OBJECT_ATTRIBUTES ObjectAttributes
;
543 UNICODE_STRING DeviceName
;
545 IO_STATUS_BLOCK Iosb
;
546 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
548 DbgPrint("CSR: CsrInitConsoleSupport()\n");
550 RtlInitUnicodeString(&DeviceName
, L
"\\??\\BlueScreen");
551 InitializeObjectAttributes(&ObjectAttributes
,
556 Status
= NtOpenFile(&ConsoleDeviceHandle
,
561 FILE_SYNCHRONOUS_IO_ALERT
);
562 if (!NT_SUCCESS(Status
))
564 DbgPrint("CSR: Failed to open console. Expect problems.\n");
566 // DbgPrint("CSR: ConsoleDeviceHandle %x\n", ConsoleDeviceHandle);
568 RtlInitUnicodeString(&DeviceName
, L
"\\??\\Keyboard");
569 InitializeObjectAttributes(&ObjectAttributes
,
574 Status
= NtOpenFile(&KeyboardDeviceHandle
,
580 if (!NT_SUCCESS(Status
))
582 DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
586 RtlInitializeCriticalSection( &ActiveConsoleLock
);
587 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
, 0, 0, &ScrInfo
, sizeof( ScrInfo
) );
588 if( !NT_SUCCESS( Status
) )
590 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
593 PhysicalConsoleSize
= ScrInfo
.dwSize
;
596 VOID
Console_Api( DWORD RefreshEvent
)
598 /* keep reading events from the keyboard and stuffing them into the current
599 console's input queue */
600 ConsoleInput
*KeyEventRecord
;
601 ConsoleInput
*TempInput
;
602 IO_STATUS_BLOCK Iosb
;
604 HANDLE Events
[2]; // 0 = keyboard, 1 = refresh
607 PCSRSS_CONSOLE SwapConsole
= 0; // console we are thinking about swapping with
610 Status
= NtCreateEvent( &Events
[0], STANDARD_RIGHTS_ALL
, NULL
, FALSE
, FALSE
);
611 if( !NT_SUCCESS( Status
) )
613 DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status
);
614 NtTerminateProcess( NtCurrentProcess(), Status
);
616 Events
[1] = (HANDLE
)RefreshEvent
;
619 KeyEventRecord
= RtlAllocateHeap(CsrssApiHeap
,
621 sizeof(ConsoleInput
));
622 if ( KeyEventRecord
== 0 )
624 DbgPrint( "CSR: Memory allocation failure!" );
627 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
628 Status
= NtReadFile( KeyboardDeviceHandle
, Events
[0], NULL
, NULL
, &Iosb
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
, sizeof( KEY_EVENT_RECORD
), NULL
, 0 );
629 if( !NT_SUCCESS( Status
) )
631 DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
632 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
635 if( Status
== STATUS_PENDING
)
639 Status
= NtWaitForMultipleObjects( 2, Events
, WaitAny
, FALSE
, NULL
);
640 if( Status
== STATUS_WAIT_0
+ 1 )
643 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
647 else if( Status
!= STATUS_WAIT_0
)
649 DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status
);
650 NtTerminateProcess( NtCurrentProcess(), Status
);
655 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
& ( RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
)&& KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_TAB
)
656 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
)
661 unsigned int src
, dst
;
663 /* alt-tab, swap consoles */
664 // move SwapConsole to next console, and print its title
667 SwapConsole
= ActiveConsole
;
669 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
)
670 SwapConsole
= SwapConsole
->Prev
;
671 else SwapConsole
= SwapConsole
->Next
;
672 Title
.MaximumLength
= RtlUnicodeStringToAnsiSize( &SwapConsole
->Title
);
674 Buffer
= RtlAllocateHeap( CsrssApiHeap
,
676 sizeof( COORD
) + Title
.MaximumLength
);
677 pos
= (COORD
*)Buffer
;
678 Title
.Buffer
= Buffer
+ sizeof( COORD
);
680 /* this does not seem to work
681 RtlUnicodeStringToAnsiString( &Title, &SwapConsole->Title, FALSE ); */
683 for( src
= 0, dst
= 0; src
< SwapConsole
->Title
.Length
; src
++, dst
++ )
684 Title
.Buffer
[dst
] = (char)SwapConsole
->Title
.Buffer
[dst
];
686 pos
->Y
= PhysicalConsoleSize
.Y
/ 2;
687 pos
->X
= ( PhysicalConsoleSize
.X
- Title
.MaximumLength
) / 2;
688 // redraw the console to clear off old title
689 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
690 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
695 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
699 sizeof (COORD
) + Title
.MaximumLength
);
700 if( !NT_SUCCESS( Status
) )
702 DPRINT1( "Error writing to console\n" );
704 RtlFreeHeap( CsrssApiHeap
, 0, Buffer
);
707 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
711 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
714 else if( SwapConsole
&&
715 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_MENU
&&
716 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
)
718 // alt key released, swap consoles
722 if( SwapConsole
!= ActiveConsole
)
724 // first remove swapconsole from the list
725 SwapConsole
->Prev
->Next
= SwapConsole
->Next
;
726 SwapConsole
->Next
->Prev
= SwapConsole
->Prev
;
727 // now insert before activeconsole
728 SwapConsole
->Next
= ActiveConsole
;
729 SwapConsole
->Prev
= ActiveConsole
->Prev
;
730 ActiveConsole
->Prev
->Next
= SwapConsole
;
731 ActiveConsole
->Prev
= SwapConsole
;
733 ActiveConsole
= SwapConsole
;
735 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
739 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
) )
741 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
)
743 /* scroll up or down */
745 if( ActiveConsole
== 0 )
747 DbgPrint( "CSR: No Active Console!\n" );
749 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
752 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)
754 /* only scroll up if there is room to scroll up into */
755 if( ActiveConsole
->ActiveBuffer
->ShowY
!= ((ActiveConsole
->ActiveBuffer
->CurrentY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
) )
756 ActiveConsole
->ActiveBuffer
->ShowY
= (ActiveConsole
->ActiveBuffer
->ShowY
+ ActiveConsole
->ActiveBuffer
->MaxY
- 1) % ActiveConsole
->ActiveBuffer
->MaxY
;
758 else if( ActiveConsole
->ActiveBuffer
->ShowY
!= ActiveConsole
->ActiveBuffer
->CurrentY
)
759 /* only scroll down if there is room to scroll down into */
760 if( ActiveConsole
->ActiveBuffer
->ShowY
% ActiveConsole
->ActiveBuffer
->MaxY
!= ActiveConsole
->ActiveBuffer
->CurrentY
)
761 if( ((ActiveConsole
->ActiveBuffer
->CurrentY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
) != (ActiveConsole
->ActiveBuffer
->ShowY
+ PhysicalConsoleSize
.Y
) % ActiveConsole
->ActiveBuffer
->MaxY
)
762 ActiveConsole
->ActiveBuffer
->ShowY
= (ActiveConsole
->ActiveBuffer
->ShowY
+ 1) % ActiveConsole
->ActiveBuffer
->MaxY
;
763 CsrDrawConsole( ActiveConsole
->ActiveBuffer
);
766 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
770 if( ActiveConsole
== 0 )
772 DbgPrint( "CSR: No Active Console!\n" );
774 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
777 // process special keys if enabled
778 if( ActiveConsole
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
) )
779 switch( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
782 // add a \n to the queue as well
784 updown
= KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
;
785 KeyEventRecord
->Echoed
= FALSE
;
786 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\r';
787 KeyEventRecord
->ListEntry
.Flink
= &ActiveConsole
->InputEvents
;
788 KeyEventRecord
->ListEntry
.Blink
= ActiveConsole
->InputEvents
.Blink
;
789 ActiveConsole
->InputEvents
.Blink
->Flink
= &KeyEventRecord
->ListEntry
;
790 ActiveConsole
->InputEvents
.Blink
= &KeyEventRecord
->ListEntry
;
791 ActiveConsole
->WaitingChars
++;
792 KeyEventRecord
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( ConsoleInput
) );
793 if( !KeyEventRecord
)
795 DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
799 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
800 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
= updown
;
801 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
= 0;
802 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualScanCode
= 0;
803 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\n';
805 // add event to the queue
806 KeyEventRecord
->ListEntry
.Flink
= &ActiveConsole
->InputEvents
;
807 KeyEventRecord
->ListEntry
.Blink
= ActiveConsole
->InputEvents
.Blink
;
808 ActiveConsole
->InputEvents
.Blink
->Flink
= &KeyEventRecord
->ListEntry
;
809 ActiveConsole
->InputEvents
.Blink
= &KeyEventRecord
->ListEntry
;
810 // if line input mode is enabled, only wake the client on enter key down
811 if( !(ActiveConsole
->Mode
& ENABLE_LINE_INPUT
) ||
812 ( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' &&
813 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
) )
815 NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
816 if( KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' )
817 ActiveConsole
->WaitingLines
++;
819 KeyEventRecord
->Echoed
= FALSE
;
820 if( ActiveConsole
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
) &&
821 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\b' &&
822 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
)
824 // walk the input queue looking for a char to backspace
825 for( TempInput
= (ConsoleInput
*)ActiveConsole
->InputEvents
.Blink
;
826 TempInput
!= (ConsoleInput
*)&ActiveConsole
->InputEvents
&&
827 (TempInput
->InputEvent
.EventType
!= KEY_EVENT
||
828 TempInput
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
||
829 TempInput
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\b' );
830 TempInput
= (ConsoleInput
*)TempInput
->ListEntry
.Blink
);
831 // if we found one, delete it, otherwise, wake the client
832 if( TempInput
!= (ConsoleInput
*)&ActiveConsole
->InputEvents
)
834 // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
835 TempInput
->ListEntry
.Blink
->Flink
= TempInput
->ListEntry
.Flink
;
836 TempInput
->ListEntry
.Flink
->Blink
= TempInput
->ListEntry
.Blink
;
837 if( TempInput
->Echoed
)
838 CsrpWriteConsole( ActiveConsole
->ActiveBuffer
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
839 RtlFreeHeap( CsrssApiHeap
, 0, TempInput
);
840 KeyEventRecord
->ListEntry
.Blink
->Flink
= KeyEventRecord
->ListEntry
.Flink
;
841 KeyEventRecord
->ListEntry
.Flink
->Blink
= KeyEventRecord
->ListEntry
.Blink
;
842 RtlFreeHeap( CsrssApiHeap
, 0, KeyEventRecord
);
843 ActiveConsole
->WaitingChars
-= 2;
845 else NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
848 // echo chars if we are supposed to and client is waiting for some
849 if( ActiveConsole
->Mode
& ENABLE_ECHO_INPUT
&& ActiveConsole
->EchoCount
&&
850 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
&&
851 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
== TRUE
&&
852 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
!= '\r' )
854 // mark the char as already echoed
855 CsrpWriteConsole( ActiveConsole
->ActiveBuffer
, &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
856 ActiveConsole
->EchoCount
--;
857 KeyEventRecord
->Echoed
= TRUE
;
860 ActiveConsole
->WaitingChars
++;
861 if( !(ActiveConsole
->Mode
& ENABLE_LINE_INPUT
) )
862 NtSetEvent( ActiveConsole
->ActiveEvent
, 0 );
867 CSR_API(CsrGetScreenBufferInfo
)
870 PCSRSS_SCREEN_BUFFER Buff
;
871 PCONSOLE_SCREEN_BUFFER_INFO pInfo
;
872 IO_STATUS_BLOCK Iosb
;
874 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
875 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
876 sizeof(LPC_MESSAGE_HEADER
);
879 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.ScreenBufferInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
882 return Reply
->Status
= STATUS_INVALID_HANDLE
;
884 pInfo
= &Reply
->Data
.ScreenBufferInfoReply
.Info
;
885 if( Buff
== ActiveConsole
->ActiveBuffer
)
887 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
, 0, 0, pInfo
, sizeof( *pInfo
) );
888 if( !NT_SUCCESS( Status
) )
889 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
890 Reply
->Status
= Status
;
893 pInfo
->dwSize
.X
= PhysicalConsoleSize
.X
;
894 pInfo
->dwSize
.Y
= PhysicalConsoleSize
.Y
;
895 pInfo
->dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
896 pInfo
->dwCursorPosition
.Y
= (Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
897 pInfo
->wAttributes
= Buff
->DefaultAttrib
;
898 pInfo
->srWindow
.Left
= 0;
899 pInfo
->srWindow
.Right
= PhysicalConsoleSize
.X
- 1;
900 pInfo
->srWindow
.Top
= 0;
901 pInfo
->srWindow
.Bottom
= PhysicalConsoleSize
.Y
- 1;
902 Reply
->Status
= STATUS_SUCCESS
;
905 return Reply
->Status
;
908 CSR_API(CsrSetCursor
)
911 PCSRSS_SCREEN_BUFFER Buff
;
912 CONSOLE_SCREEN_BUFFER_INFO Info
;
913 IO_STATUS_BLOCK Iosb
;
915 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
916 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
917 sizeof(LPC_MESSAGE_HEADER
);
920 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.SetCursorRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
923 return Reply
->Status
= STATUS_INVALID_HANDLE
;
925 Info
.dwCursorPosition
= Request
->Data
.SetCursorRequest
.Position
;
926 Info
.wAttributes
= Buff
->DefaultAttrib
;
927 if( Buff
== ActiveConsole
->ActiveBuffer
)
929 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &Info
, sizeof( Info
), 0, 0 );
930 if( !NT_SUCCESS( Status
) )
931 DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
933 Buff
->CurrentX
= Info
.dwCursorPosition
.X
+ Buff
->ShowX
;
934 Buff
->CurrentY
= (Info
.dwCursorPosition
.Y
+ Buff
->ShowY
) % Buff
->MaxY
;
936 return Reply
->Status
= Status
;
939 CSR_API(CsrWriteConsoleOutputChar
)
941 BYTE
*Buffer
= Request
->Data
.WriteConsoleOutputCharRequest
.String
;
942 PCSRSS_SCREEN_BUFFER Buff
;
945 IO_STATUS_BLOCK Iosb
;
947 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
948 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
949 sizeof(LPC_MESSAGE_HEADER
);
951 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleOutputCharRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
954 return Reply
->Status
= STATUS_INVALID_HANDLE
;
958 Buff
->CurrentX
= Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.X
;
959 Buff
->CurrentY
= Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.Y
;
960 Buffer
[Request
->Data
.WriteConsoleOutputCharRequest
.Length
] = 0;
961 CsrpWriteConsole( Buff
, Buffer
, Request
->Data
.WriteConsoleOutputCharRequest
.Length
, FALSE
);
962 if( ActiveConsole
->ActiveBuffer
== Buff
)
964 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
969 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
972 &Request
->Data
.WriteConsoleOutputCharRequest
.Coord
,
973 sizeof (COORD
) + Request
->Data
.WriteConsoleOutputCharRequest
.Length
);
974 if( !NT_SUCCESS( Status
) )
975 DPRINT1( "Failed to write output chars: %x\n", Status
);
977 Reply
->Data
.WriteConsoleOutputCharReply
.EndCoord
.X
= Buff
->CurrentX
- Buff
->ShowX
;
978 Reply
->Data
.WriteConsoleOutputCharReply
.EndCoord
.Y
= (Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
982 return Reply
->Status
= STATUS_SUCCESS
;
985 CSR_API(CsrFillOutputChar
)
987 PCSRSS_SCREEN_BUFFER Buff
;
990 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
991 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
992 sizeof(LPC_MESSAGE_HEADER
);
995 if( !NT_SUCCESS( CsrGetObject( ProcessData
, Request
->Data
.FillOutputRequest
.ConsoleHandle
, (Object_t
**)&Buff
) ) || Buff
->Header
.Type
!= CSRSS_SCREEN_BUFFER_MAGIC
)
998 return Reply
->Status
= STATUS_INVALID_HANDLE
;
1000 X
= Request
->Data
.FillOutputRequest
.Position
.X
+ Buff
->ShowX
;
1001 Y
= Request
->Data
.FillOutputRequest
.Position
.Y
+ Buff
->ShowY
;
1002 for( i
= 0; i
< 20000; i
++ );
1003 for( i
= 0; i
< Request
->Data
.FillOutputRequest
.Length
; i
++ )
1005 Buff
->Buffer
[ (Y
* 2 * Buff
->MaxX
) + (X
* 2) ] = Request
->Data
.FillOutputRequest
.Char
;
1006 if( ++X
== Buff
->MaxX
)
1008 if( ++Y
== Buff
->MaxY
)
1013 if( Buff
== ActiveConsole
->ActiveBuffer
)
1014 CsrDrawConsole( Buff
);
1016 return Reply
->Status
;
1019 CSR_API(CsrReadInputEvent
)
1021 PCSRSS_CONSOLE Console
;
1023 ConsoleInput
*Input
;
1025 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1026 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1027 sizeof(LPC_MESSAGE_HEADER
);
1028 Reply
->Data
.ReadInputReply
.Event
= ProcessData
->ConsoleEvent
;
1031 Status
= CsrGetObject( ProcessData
, Request
->Data
.ReadInputRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1032 if( !NT_SUCCESS( Status
) || (Status
= Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1034 Reply
->Status
= Status
;
1038 // 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
1039 if( Console
->InputEvents
.Flink
!= &Console
->InputEvents
&&
1040 ( !Console
->Mode
& ENABLE_LINE_INPUT
|| Console
->WaitingLines
) )
1042 Input
= (ConsoleInput
*)Console
->InputEvents
.Flink
;
1043 Input
->ListEntry
.Blink
->Flink
= Input
->ListEntry
.Flink
;
1044 Input
->ListEntry
.Flink
->Blink
= Input
->ListEntry
.Blink
;
1045 Reply
->Data
.ReadInputReply
.Input
= Input
->InputEvent
;
1046 if( Console
->Mode
& ENABLE_LINE_INPUT
&&
1047 Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
== FALSE
&&
1048 Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
== '\n' )
1049 Console
->WaitingLines
--;
1050 Console
->WaitingChars
--;
1051 RtlFreeHeap( CsrssApiHeap
, 0, Input
);
1052 Reply
->Data
.ReadInputReply
.MoreEvents
= (Console
->InputEvents
.Flink
!= &Console
->InputEvents
) ? TRUE
: FALSE
;
1053 Status
= STATUS_SUCCESS
;
1055 else Status
= STATUS_PENDING
;
1057 return Reply
->Status
= Status
;
1060 CSR_API(CsrWriteConsoleOutputAttrib
)
1063 PCSRSS_SCREEN_BUFFER Buff
;
1066 IO_STATUS_BLOCK Iosb
;
1068 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1069 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1070 sizeof(LPC_MESSAGE_HEADER
);
1072 Status
= CsrGetObject( ProcessData
, Request
->Data
.WriteConsoleOutputAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1073 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1075 Reply
->Status
= Status
;
1081 Buff
->CurrentX
= Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.X
+ Buff
->ShowX
;
1082 Buff
->CurrentY
= (Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.Y
+ Buff
->ShowY
) % Buff
->MaxY
;
1083 for( c
= 0; c
< Request
->Data
.WriteConsoleOutputAttribRequest
.Length
; c
++ )
1085 Buff
->Buffer
[(Buff
->CurrentY
* Buff
->MaxX
* 2) + (Buff
->CurrentX
* 2) + 1] = Request
->Data
.WriteConsoleOutputAttribRequest
.String
[c
];
1086 if( ++Buff
->CurrentX
== Buff
->MaxX
)
1089 if( ++Buff
->CurrentY
== Buff
->MaxY
)
1093 if( Buff
== ActiveConsole
->ActiveBuffer
)
1095 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
1100 IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE
,
1103 &Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
,
1104 Request
->Data
.WriteConsoleOutputAttribRequest
.Length
+
1106 if( !NT_SUCCESS( Status
) )
1107 DPRINT1( "Failed to write output attributes to console\n" );
1109 Reply
->Data
.WriteConsoleOutputAttribReply
.EndCoord
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1110 Reply
->Data
.WriteConsoleOutputAttribReply
.EndCoord
.Y
= ( Buff
->CurrentY
+ Buff
->MaxY
- Buff
->ShowY
) % Buff
->MaxY
;
1114 return Reply
->Status
= STATUS_SUCCESS
;
1117 CSR_API(CsrFillOutputAttrib
)
1120 PCSRSS_SCREEN_BUFFER Buff
;
1123 IO_STATUS_BLOCK Iosb
;
1124 OUTPUT_ATTRIBUTE Attr
;
1126 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1127 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1128 sizeof(LPC_MESSAGE_HEADER
);
1130 Status
= CsrGetObject( ProcessData
, Request
->Data
.FillOutputAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1131 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1133 Reply
->Status
= Status
;
1139 Buff
->CurrentX
= Request
->Data
.FillOutputAttribRequest
.Coord
.X
+ Buff
->ShowX
;
1140 Buff
->CurrentY
= Request
->Data
.FillOutputAttribRequest
.Coord
.Y
+ Buff
->ShowY
;
1141 for( c
= 0; c
< Request
->Data
.FillOutputAttribRequest
.Length
; c
++ )
1143 Buff
->Buffer
[(Buff
->CurrentY
* Buff
->MaxX
* 2) + (Buff
->CurrentX
* 2) + 1] = Request
->Data
.FillOutputAttribRequest
.Attribute
;
1144 if( ++Buff
->CurrentX
== Buff
->MaxX
)
1147 if( ++Buff
->CurrentY
== Buff
->MaxY
)
1151 if( Buff
== ActiveConsole
->ActiveBuffer
)
1153 Attr
.wAttribute
= Request
->Data
.FillOutputAttribRequest
.Attribute
;
1154 Attr
.nLength
= Request
->Data
.FillOutputAttribRequest
.Length
;
1155 Attr
.dwCoord
= Request
->Data
.FillOutputAttribRequest
.Coord
;
1156 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
,
1161 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE
,
1166 if( !NT_SUCCESS( Status
) )
1167 DPRINT1( "Failed to fill output attribute\n" );
1172 return Reply
->Status
= STATUS_SUCCESS
;
1176 CSR_API(CsrGetCursorInfo
)
1178 PCSRSS_SCREEN_BUFFER Buff
;
1181 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1182 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1183 sizeof(LPC_MESSAGE_HEADER
);
1185 Status
= CsrGetObject( ProcessData
, Request
->Data
.GetCursorInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1186 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1188 Reply
->Status
= Status
;
1192 Reply
->Data
.GetCursorInfoReply
.Info
= Buff
->CursorInfo
;
1194 return Reply
->Status
= STATUS_SUCCESS
;
1197 CSR_API(CsrSetCursorInfo
)
1199 PCSRSS_SCREEN_BUFFER Buff
;
1201 IO_STATUS_BLOCK Iosb
;
1203 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1204 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1205 sizeof(LPC_MESSAGE_HEADER
);
1207 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetCursorInfoRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1208 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1210 Reply
->Status
= Status
;
1214 Buff
->CursorInfo
= Request
->Data
.SetCursorInfoRequest
.Info
;
1215 if( Buff
== ActiveConsole
->ActiveBuffer
)
1217 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_CURSOR_INFO
, &Buff
->CursorInfo
, sizeof( Buff
->CursorInfo
), 0, 0 );
1218 if( !NT_SUCCESS( Status
) )
1220 DbgPrint( "CSR: Failed to set cursor info\n" );
1221 return Reply
->Status
= Status
;
1225 return Reply
->Status
= STATUS_SUCCESS
;
1228 CSR_API(CsrSetTextAttrib
)
1231 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
1232 IO_STATUS_BLOCK Iosb
;
1233 PCSRSS_SCREEN_BUFFER Buff
;
1235 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1236 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) -
1237 sizeof(LPC_MESSAGE_HEADER
);
1239 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetAttribRequest
.ConsoleHandle
, (Object_t
**)&Buff
);
1240 if( !NT_SUCCESS( Status
) || (Status
= Buff
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
? 0 : STATUS_INVALID_HANDLE
))
1242 Reply
->Status
= Status
;
1246 Buff
->DefaultAttrib
= Request
->Data
.SetAttribRequest
.Attrib
;
1247 if( Buff
== ActiveConsole
->ActiveBuffer
)
1249 ScrInfo
.wAttributes
= Buff
->DefaultAttrib
;
1250 ScrInfo
.dwCursorPosition
.X
= Buff
->CurrentX
- Buff
->ShowX
;
1251 ScrInfo
.dwCursorPosition
.Y
= ((Buff
->CurrentY
+ Buff
->MaxY
) - Buff
->ShowY
) % Buff
->MaxY
;
1252 Status
= NtDeviceIoControlFile( ConsoleDeviceHandle
, NULL
, NULL
, NULL
, &Iosb
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
, &ScrInfo
, sizeof( ScrInfo
), 0, 0 );
1253 if( !NT_SUCCESS( Status
) )
1255 DbgPrint( "CSR: Failed to set console info\n" );
1257 return Reply
->Status
= Status
;
1261 return Reply
->Status
= STATUS_SUCCESS
;
1264 CSR_API(CsrSetConsoleMode
)
1267 PCSRSS_CONSOLE Console
;
1268 PCSRSS_SCREEN_BUFFER Buff
;
1270 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1271 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1273 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetConsoleModeRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1274 if( !NT_SUCCESS( Status
) )
1276 Reply
->Status
= Status
;
1280 Buff
= (PCSRSS_SCREEN_BUFFER
)Console
;
1281 if( Console
->Header
.Type
== CSRSS_CONSOLE_MAGIC
)
1282 Console
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_INPUT_MODE_VALID
;
1283 else if( Console
->Header
.Type
== CSRSS_SCREEN_BUFFER_MAGIC
)
1284 Buff
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_OUTPUT_MODE_VALID
;
1286 Reply
->Status
= STATUS_INVALID_HANDLE
;
1291 Reply
->Status
= STATUS_SUCCESS
;
1292 return Reply
->Status
;
1295 CSR_API(CsrGetConsoleMode
)
1298 PCSRSS_CONSOLE Console
;
1299 PCSRSS_SCREEN_BUFFER Buff
; /* gee, I really wish I could use an anonymous union here */
1301 Reply
->Header
.MessageSize
= sizeof(CSRSS_API_REPLY
);
1302 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1304 Status
= CsrGetObject( ProcessData
, Request
->Data
.GetConsoleModeRequest
.ConsoleHandle
, (Object_t
**)&Console
);
1305 if( !NT_SUCCESS( Status
) )
1307 Reply
->Status
= Status
;
1311 Reply
->Status
= STATUS_SUCCESS
;
1312 Buff
= (PCSRSS_SCREEN_BUFFER
)Console
;
1313 if( Console
->Header
.Type
= CSRSS_CONSOLE_MAGIC
)
1314 Reply
->Data
.GetConsoleModeReply
.ConsoleMode
= Console
->Mode
;
1315 else if( Buff
->Header
.Type
= CSRSS_SCREEN_BUFFER_MAGIC
)
1316 Reply
->Data
.GetConsoleModeReply
.ConsoleMode
= Buff
->Mode
;
1317 else Status
= STATUS_INVALID_HANDLE
;
1319 return Reply
->Status
;
1322 CSR_API(CsrCreateScreenBuffer
)
1324 PCSRSS_SCREEN_BUFFER Buff
= RtlAllocateHeap( CsrssApiHeap
, 0, sizeof( CSRSS_SCREEN_BUFFER
) );
1327 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1328 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1330 Reply
->Status
= STATUS_INSUFFICIENT_RESOURCES
;
1332 Status
= CsrInitConsoleScreenBuffer( Buff
);
1333 if( !NT_SUCCESS( Status
) )
1334 Reply
->Status
= Status
;
1336 Status
= CsrInsertObject( ProcessData
, &Reply
->Data
.CreateScreenBufferReply
.OutputHandle
, &Buff
->Header
);
1337 if( !NT_SUCCESS( Status
) )
1338 Reply
->Status
= Status
;
1339 else Reply
->Status
= STATUS_SUCCESS
;
1342 return Reply
->Status
;
1345 CSR_API(CsrSetScreenBuffer
)
1348 PCSRSS_SCREEN_BUFFER Buff
;
1350 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1351 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1353 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetActiveScreenBufferRequest
.OutputHandle
, (Object_t
**)&Buff
);
1354 if( !NT_SUCCESS( Status
) )
1355 Reply
->Status
= Status
;
1357 // drop reference to old buffer, maybe delete
1358 if( !InterlockedDecrement( &ProcessData
->Console
->ActiveBuffer
->Header
.ReferenceCount
) )
1359 CsrDeleteScreenBuffer( ProcessData
->Console
->ActiveBuffer
);
1360 // tie console to new buffer
1361 ProcessData
->Console
->ActiveBuffer
= Buff
;
1362 // inc ref count on new buffer
1363 InterlockedIncrement( &Buff
->Header
.ReferenceCount
);
1364 // if the console is active, redraw it
1365 if( ActiveConsole
== ProcessData
->Console
)
1366 CsrDrawConsole( Buff
);
1367 Reply
->Status
= STATUS_SUCCESS
;
1370 return Reply
->Status
;
1373 CSR_API(CsrSetTitle
)
1376 PCSRSS_CONSOLE Console
;
1378 Reply
->Header
.MessageSize
= sizeof( CSRSS_API_REPLY
);
1379 Reply
->Header
.DataSize
= sizeof(CSRSS_API_REPLY
) - sizeof(LPC_MESSAGE_HEADER
);
1381 Status
= CsrGetObject( ProcessData
, Request
->Data
.SetTitleRequest
.Console
, (Object_t
**)&Console
);
1382 if( !NT_SUCCESS( Status
) )
1383 Reply
->Status
= Status
;
1385 // copy title to console
1386 RtlFreeUnicodeString( &Console
->Title
);
1387 RtlCreateUnicodeString( &Console
->Title
, Request
->Data
.SetTitleRequest
.Title
);
1388 Reply
->Status
= STATUS_SUCCESS
;
1391 return Reply
->Status
;
1394 CSR_API(CsrGetTitle
)
1397 PCSRSS_CONSOLE Console
;
1399 Reply
->Header
.MessageSize
= sizeof (CSRSS_API_REPLY
);
1400 Reply
->Header
.DataSize
=
1401 sizeof (CSRSS_API_REPLY
)
1402 - sizeof(LPC_MESSAGE_HEADER
);
1404 Status
= CsrGetObject (
1406 Request
->Data
.GetTitleRequest
.ConsoleHandle
,
1407 (Object_t
**) & Console
1409 if ( !NT_SUCCESS( Status
) )
1411 Reply
->Status
= Status
;
1415 HANDLE ConsoleHandle
= Request
->Data
.GetTitleRequest
.ConsoleHandle
;
1417 /* Copy title of the console to the user title buffer */
1419 & Reply
->Data
.GetTitleReply
,
1420 sizeof (CSRSS_GET_TITLE_REPLY
)
1422 Reply
->Data
.GetTitleReply
.ConsoleHandle
= ConsoleHandle
;
1423 Reply
->Data
.GetTitleReply
.Length
= Console
->Title
.Length
;
1424 wcscpy (Reply
->Data
.GetTitleReply
.Title
, Console
->Title
.Buffer
);
1425 Reply
->Status
= STATUS_SUCCESS
;
1428 return Reply
->Status
;