Create console active event inheritable.
[reactos.git] / reactos / subsys / csrss / api / conio.c
1 /* $Id: conio.c,v 1.30 2002/05/07 22:44:23 hbirr Exp $
2 *
3 * reactos/subsys/csrss/api/conio.c
4 *
5 * Console I/O functions
6 *
7 * ReactOS Operating System
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ddk/ntddk.h>
13
14 #include <csrss/csrss.h>
15 #include "api.h"
16 #include <ntdll/rtl.h>
17 #include <ddk/ntddblue.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22 #define LOCK RtlEnterCriticalSection(&ActiveConsoleLock)
23 #define UNLOCK RtlLeaveCriticalSection(&ActiveConsoleLock)
24
25 /* FIXME: Is there a way to create real aliasses with gcc? [CSH] */
26 #define ALIAS(Name, Target) typeof(Target) Name = Target
27
28
29 /* GLOBALS *******************************************************************/
30
31 static HANDLE ConsoleDeviceHandle;
32 static HANDLE KeyboardDeviceHandle;
33 static PCSRSS_CONSOLE ActiveConsole;
34 CRITICAL_SECTION ActiveConsoleLock;
35 static COORD PhysicalConsoleSize;
36
37 /* FUNCTIONS *****************************************************************/
38
39 CSR_API(CsrAllocConsole)
40 {
41 PCSRSS_CONSOLE Console;
42 HANDLE Process;
43 NTSTATUS Status;
44 CLIENT_ID ClientId;
45
46 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
47 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
48 sizeof(LPC_MESSAGE_HEADER);
49 if( ProcessData->Console )
50 {
51 Reply->Status = STATUS_INVALID_PARAMETER;
52 return STATUS_INVALID_PARAMETER;
53 }
54 Reply->Status = STATUS_SUCCESS;
55 Console = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_CONSOLE ) );
56 if( Console == 0 )
57 {
58 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
59 return STATUS_INSUFFICIENT_RESOURCES;
60 }
61 Reply->Status = CsrInitConsole( Console );
62 if( !NT_SUCCESS( Reply->Status ) )
63 {
64 RtlFreeHeap( CsrssApiHeap, 0, Console );
65 return Reply->Status;
66 }
67 ProcessData->Console = Console;
68 /* add a reference count because the process is tied to the console */
69 Console->Header.ReferenceCount++;
70 Status = CsrInsertObject( ProcessData, &Reply->Data.AllocConsoleReply.InputHandle, &Console->Header );
71 if( !NT_SUCCESS( Status ) )
72 {
73 CsrDeleteConsole( Console );
74 ProcessData->Console = 0;
75 return Reply->Status = Status;
76 }
77 Status = CsrInsertObject( ProcessData, &Reply->Data.AllocConsoleReply.OutputHandle, &Console->ActiveBuffer->Header );
78 if( !NT_SUCCESS( Status ) )
79 {
80 Console->Header.ReferenceCount--;
81 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
82 ProcessData->Console = 0;
83 return Reply->Status = Status;
84 }
85 ClientId.UniqueProcess = (HANDLE)ProcessData->ProcessId;
86 Status = NtOpenProcess( &Process, PROCESS_DUP_HANDLE, 0, &ClientId );
87 if( !NT_SUCCESS( Status ) )
88 {
89 DbgPrint( "CSR: NtOpenProcess() failed for handle duplication\n" );
90 Console->Header.ReferenceCount--;
91 ProcessData->Console = 0;
92 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.OutputHandle );
93 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
94 Reply->Status = Status;
95 return Status;
96 }
97 Status = NtDuplicateObject( NtCurrentProcess(), ProcessData->Console->ActiveEvent, Process, &ProcessData->ConsoleEvent, SYNCHRONIZE, FALSE, 0 );
98 if( !NT_SUCCESS( Status ) )
99 {
100 DbgPrint( "CSR: NtDuplicateObject() failed: %x\n", Status );
101 NtClose( Process );
102 Console->Header.ReferenceCount--;
103 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.OutputHandle );
104 CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
105 ProcessData->Console = 0;
106 Reply->Status = Status;
107 return Status;
108 }
109 NtClose( Process );
110 return STATUS_SUCCESS;
111 }
112
113 CSR_API(CsrFreeConsole)
114 {
115 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
116 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
117 sizeof(LPC_MESSAGE_HEADER);
118
119 Reply->Status = STATUS_NOT_IMPLEMENTED;
120
121 return(STATUS_NOT_IMPLEMENTED);
122 }
123
124 CSR_API(CsrReadConsole)
125 {
126 PLIST_ENTRY CurrentEntry;
127 ConsoleInput *Input;
128 PCHAR Buffer;
129 int i = 0;
130 ULONG nNumberOfCharsToRead;
131 PCSRSS_CONSOLE Console;
132 NTSTATUS Status;
133
134 /* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
135 nNumberOfCharsToRead = Request->Data.ReadConsoleRequest.NrCharactersToRead > CSRSS_MAX_READ_CONSOLE_REQUEST ? CSRSS_MAX_READ_CONSOLE_REQUEST : Request->Data.ReadConsoleRequest.NrCharactersToRead;
136 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
137 Reply->Header.DataSize = Reply->Header.MessageSize -
138 sizeof(LPC_MESSAGE_HEADER);
139 Buffer = Reply->Data.ReadConsoleReply.Buffer;
140 Reply->Data.ReadConsoleReply.EventHandle = ProcessData->ConsoleEvent;
141 LOCK;
142 Status = CsrGetObject( ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle, (Object_t **)&Console );
143 if( !NT_SUCCESS( Status ) )
144 {
145 Reply->Status = Status;
146 UNLOCK;
147 return Status;
148 }
149 if( Console->Header.Type != CSRSS_CONSOLE_MAGIC )
150 {
151 Reply->Status = STATUS_INVALID_HANDLE;
152 UNLOCK;
153 return STATUS_INVALID_HANDLE;
154 }
155 for (; i<nNumberOfCharsToRead && Console->InputEvents.Flink != &Console->InputEvents; i++ )
156 {
157 // remove input event from queue
158 CurrentEntry = RemoveHeadList(&Console->InputEvents);
159 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
160
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 )
165 {
166 // backspace handling
167 if( Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' )
168 {
169 // echo if it has not already been done, and either we or the client has chars to be deleted
170 if( !Input->Echoed && ( i || Request->Data.ReadConsoleRequest.nCharsCanBeDeleted ) )
171 CsrpWriteConsole( Console->ActiveBuffer, &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
172 if( i )
173 i-=2; // if we already have something to return, just back it up by 2
174 else
175 { // otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer
176 Reply->Data.ReadConsoleReply.NrCharactersRead = 0;
177 Reply->Status = STATUS_NOTIFY_CLEANUP;
178 Console->WaitingChars--;
179 RtlFreeHeap( CsrssApiHeap, 0, Input );
180 UNLOCK;
181 return STATUS_NOTIFY_CLEANUP;
182 }
183 Request->Data.ReadConsoleRequest.nCharsCanBeDeleted--;
184 Input->Echoed = TRUE; // mark as echoed so we don't echo it below
185 }
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 &&
190 !Input->Echoed &&
191 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
192 CsrpWriteConsole( Console->ActiveBuffer, &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
193 }
194 else i--;
195 Console->WaitingChars--;
196 RtlFreeHeap( CsrssApiHeap, 0, Input );
197 }
198 Reply->Data.ReadConsoleReply.NrCharactersRead = i;
199 if( !i )
200 Reply->Status = STATUS_PENDING; // we didn't read anything
201 else if( Console->Mode & ENABLE_LINE_INPUT )
202 if( !Console->WaitingLines || Buffer[i-1] != '\n' )
203 {
204 Reply->Status = STATUS_PENDING; // line buffered, didn't get a complete line
205 }
206 else {
207 Console->WaitingLines--;
208 Reply->Status = STATUS_SUCCESS; // line buffered, did get a complete line
209 }
210 else Reply->Status = STATUS_SUCCESS; // not line buffered, did read something
211 if( Reply->Status == STATUS_PENDING )
212 {
213 Console->EchoCount = nNumberOfCharsToRead - i;
214 }
215 else {
216 Console->EchoCount = 0; // if the client is no longer waiting on input, do not echo
217 }
218 Reply->Header.MessageSize += i;
219 UNLOCK;
220 return Reply->Status;
221 }
222
223 #define GET_CELL_BUFFER(b,o)\
224 (b)->Buffer[(o)++];
225
226 #define SET_CELL_BUFFER(b,o,c,a)\
227 (b)->Buffer[(o)++]=(c);\
228 (b)->Buffer[(o)++]=(a);
229
230 static VOID FASTCALL
231 ClearLineBuffer (
232 PCSRSS_SCREEN_BUFFER Buff,
233 DWORD StartX
234 )
235 {
236 DWORD Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + StartX);
237
238 for ( ; StartX < Buff->MaxX; StartX ++ )
239 {
240 /* Fill the cell: Offset is incremented by the macro */
241 SET_CELL_BUFFER(Buff,Offset,' ',Buff->DefaultAttrib)
242 }
243 }
244
245 NTSTATUS STDCALL CsrpWriteConsole( PCSRSS_SCREEN_BUFFER Buff, CHAR *Buffer, DWORD Length, BOOL Attrib )
246 {
247 IO_STATUS_BLOCK Iosb;
248 NTSTATUS Status;
249 int i;
250 DWORD Offset;
251
252 for( i = 0; i < Length; i++ )
253 {
254 switch( Buffer[ i ] )
255 {
256 /* --- LF --- */
257 case '\n':
258 Buff->CurrentX = 0;
259 /* slide the viewable screen */
260 if( ((PhysicalConsoleSize.Y + Buff->ShowY) % Buff->MaxY) == (Buff->CurrentY + 1) % Buff->MaxY)
261 if( ++Buff->ShowY == (Buff->MaxY - 1) )
262 Buff->ShowY = 0;
263 if( ++Buff->CurrentY == Buff->MaxY )
264 {
265 Buff->CurrentY = 0;
266 }
267 ClearLineBuffer (Buff, 0);
268 break;
269 /* --- BS --- */
270 case '\b':
271 if( Buff->CurrentX == 0 )
272 {
273 /* slide viewable screen up */
274 if( Buff->ShowY == Buff->CurrentY )
275 {
276 if( Buff->ShowY == 0 )
277 Buff->ShowY = Buff->MaxY;
278 else
279 Buff->ShowY--;
280 }
281 /* slide virtual position up */
282 Buff->CurrentX = Buff->MaxX;
283 if( Buff->CurrentY == 0 )
284 Buff->CurrentY = Buff->MaxY;
285 else
286 Buff->CurrentY--;
287 }
288 else
289 Buff->CurrentX--;
290 Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + Buff->CurrentX);
291 SET_CELL_BUFFER(Buff,Offset,' ',Buff->DefaultAttrib);
292 break;
293 /* --- CR --- */
294 case '\r':
295 Buff->CurrentX = 0;
296 break;
297 /* --- TAB --- */
298 case '\t':
299 CsrpWriteConsole(Buff, " ", (8 - (Buff->CurrentX % 8)), FALSE);
300 break;
301 /* --- */
302 default:
303 Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
304 Buff->Buffer[Offset ++] = Buffer[ i ];
305 if( Attrib )
306 Buff->Buffer[Offset] = Buff->DefaultAttrib;
307 Buff->CurrentX++;
308 if( Buff->CurrentX == Buff->MaxX )
309 {
310 /* if end of line, go to next */
311 Buff->CurrentX = 0;
312 if( ++Buff->CurrentY == Buff->MaxY )
313 {
314 /* if end of buffer, wrap back to beginning */
315 Buff->CurrentY = 0;
316 }
317 /* clear new line */
318 ClearLineBuffer (Buff, 0);
319 /* slide the viewable screen */
320 if( (Buff->CurrentY - Buff->ShowY) == PhysicalConsoleSize.Y )
321 if( ++Buff->ShowY == Buff->MaxY )
322 Buff->ShowY = 0;
323 }
324 }
325 }
326 if( Buff == ActiveConsole->ActiveBuffer )
327 { /* only write to screen if Console is Active, and not scrolled up */
328 if( Attrib )
329 {
330 Status = NtWriteFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, Buffer, Length, NULL, 0);
331 if (!NT_SUCCESS(Status))
332 DbgPrint("CSR: Write failed\n");
333 }
334 }
335 return(STATUS_SUCCESS);
336 }
337
338 #define CsrpInitRect(_Rect, _Top, _Left, _Bottom, _Right) \
339 { \
340 ((_Rect).Top) = _Top; \
341 ((_Rect).Left) = _Left; \
342 ((_Rect).Bottom) = _Bottom; \
343 ((_Rect).Right) = _Right; \
344 }
345
346 #define CsrpRectHeight(Rect) \
347 ((Rect.Bottom) - (Rect.Top) + 1)
348
349 #define CsrpRectWidth(Rect) \
350 ((Rect.Right) - (Rect.Left) + 1)
351
352 #define CsrpIsRectEmpty(Rect) \
353 ((Rect.Left >= Rect.Right) || (Rect.Top >= Rect.Bottom))
354
355
356 inline BOOLEAN CsrpIsEqualRect(
357 SMALL_RECT Rect1,
358 SMALL_RECT Rect2)
359 {
360 return ((Rect1.Left == Rect2.Left) && (Rect1.Right == Rect2.Right) &&
361 (Rect1.Top == Rect2.Top) && (Rect1.Bottom == Rect2.Bottom));
362 }
363
364 inline BOOLEAN CsrpGetIntersection(
365 PSMALL_RECT Intersection,
366 SMALL_RECT Rect1,
367 SMALL_RECT Rect2)
368 {
369 if (CsrpIsRectEmpty(Rect1) ||
370 (CsrpIsRectEmpty(Rect2)) ||
371 (Rect1.Top >= Rect2.Bottom) ||
372 (Rect1.Left >= Rect2.Right) ||
373 (Rect1.Bottom <= Rect2.Top) ||
374 (Rect1.Right <= Rect2.Left))
375 {
376 /* The rectangles do not intersect */
377 CsrpInitRect(*Intersection, 0, 0, 0, 0)
378 return FALSE;
379 }
380
381 CsrpInitRect(
382 *Intersection,
383 RtlMax(Rect1.Top, Rect2.Top),
384 RtlMax(Rect1.Left, Rect2.Left),
385 RtlMin(Rect1.Bottom, Rect2.Bottom),
386 RtlMin(Rect1.Right, Rect2.Right));
387 return TRUE;
388 }
389
390 inline BOOLEAN CsrpGetUnion(
391 PSMALL_RECT Union,
392 SMALL_RECT Rect1,
393 SMALL_RECT Rect2)
394 {
395 if (CsrpIsRectEmpty(Rect1))
396 {
397 if (CsrpIsRectEmpty(Rect2))
398 {
399 CsrpInitRect(*Union, 0, 0, 0, 0);
400 return FALSE;
401 }
402 else
403 *Union = Rect2;
404 }
405 else
406 {
407 if (CsrpIsRectEmpty(Rect2))
408 {
409 *Union = Rect1;
410 }
411 else
412 {
413 CsrpInitRect(
414 *Union,
415 RtlMin(Rect1.Top, Rect2.Top),
416 RtlMin(Rect1.Left, Rect2.Left),
417 RtlMax(Rect1.Bottom, Rect2.Bottom),
418 RtlMax(Rect1.Right, Rect2.Right));
419 }
420 }
421 return TRUE;
422 }
423
424 inline BOOLEAN CsrpSubtractRect(
425 PSMALL_RECT Subtraction,
426 SMALL_RECT Rect1,
427 SMALL_RECT Rect2)
428 {
429 SMALL_RECT tmp;
430
431 if (CsrpIsRectEmpty(Rect1))
432 {
433 CsrpInitRect(*Subtraction, 0, 0, 0, 0);
434 return FALSE;
435 }
436 *Subtraction = Rect1;
437 if (CsrpGetIntersection(&tmp, Rect1, Rect2))
438 {
439 if (CsrpIsEqualRect(tmp, *Subtraction))
440 {
441 CsrpInitRect(*Subtraction, 0, 0, 0, 0);
442 return FALSE;
443 }
444 if ((tmp.Top == Subtraction->Top) && (tmp.Bottom == Subtraction->Bottom))
445 {
446 if (tmp.Left == Subtraction->Left)
447 Subtraction->Left = tmp.Right;
448 else if (tmp.Right == Subtraction->Right)
449 Subtraction->Right = tmp.Left;
450 }
451 else if ((tmp.Left == Subtraction->Left) && (tmp.Right == Subtraction->Right))
452 {
453 if (tmp.Top == Subtraction->Top)
454 Subtraction->Top = tmp.Bottom;
455 else if (tmp.Bottom == Subtraction->Bottom)
456 Subtraction->Bottom = tmp.Top;
457 }
458 }
459 return TRUE;
460 }
461
462 /*
463 * Screen buffer must be locked when this function is called
464 */
465 static VOID CsrpCopyRegion(
466 PCSRSS_SCREEN_BUFFER ScreenBuffer,
467 SMALL_RECT SrcRegion,
468 SMALL_RECT DstRegion)
469 {
470 SHORT SrcY, DstY;
471 DWORD SrcOffset;
472 DWORD DstOffset;
473 DWORD BytesPerLine;
474
475 DstY = DstRegion.Top;
476 BytesPerLine = CsrpRectWidth(DstRegion) * 2;
477 for (SrcY = SrcRegion.Top; SrcY <= SrcRegion.Bottom; SrcY++)
478 {
479 SrcOffset = (SrcY * ScreenBuffer->MaxX * 2) + (SrcRegion.Left * 2);
480 DstOffset = (DstY * ScreenBuffer->MaxX * 2) + (DstRegion.Left * 2);
481 RtlCopyMemory(
482 &ScreenBuffer->Buffer[DstOffset],
483 &ScreenBuffer->Buffer[SrcOffset],
484 BytesPerLine);
485 DstY++;
486 }
487 }
488
489 /*
490 * Screen buffer must be locked when this function is called
491 */
492 static VOID CsrpFillRegion(
493 PCSRSS_SCREEN_BUFFER ScreenBuffer,
494 SMALL_RECT Region,
495 CHAR_INFO CharInfo)
496 {
497 SHORT X, Y;
498 DWORD Offset;
499
500 for (Y = Region.Top; Y <= Region.Bottom; Y++)
501 {
502 Offset = (Y * ScreenBuffer->MaxX + Region.Left) * 2;
503 for (X = Region.Left; X <= Region.Right; X++)
504 {
505 SET_CELL_BUFFER(ScreenBuffer, Offset, CharInfo.Char.AsciiChar, CharInfo.Attributes);
506 }
507 }
508 }
509
510 /*
511 * Screen buffer must be locked when this function is called
512 */
513 inline NTSTATUS CsrpSetConsoleDeviceCursor(PCSRSS_SCREEN_BUFFER ScreenBuffer, SHORT X, SHORT Y)
514 {
515 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
516 IO_STATUS_BLOCK Iosb;
517
518 ScrInfo.dwCursorPosition.X = X;
519 ScrInfo.dwCursorPosition.Y = Y;
520 ScrInfo.wAttributes = ScreenBuffer->DefaultAttrib;
521
522 return NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
523 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
524 }
525
526 /*
527 * Region - Region of virtual screen buffer to draw onto the physical console
528 * Screen buffer must be locked when this function is called
529 */
530 static VOID CsrpDrawRegion(
531 PCSRSS_SCREEN_BUFFER ScreenBuffer,
532 SMALL_RECT Region)
533 {
534 IO_STATUS_BLOCK Iosb;
535 NTSTATUS Status;
536 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
537 CONSOLE_MODE Mode;
538 int i, y;
539 DWORD BytesPerLine;
540 DWORD SrcOffset;
541 DWORD SrcDelta;
542
543 Mode.dwMode = 0; /* clear ENABLE_PROCESSED_OUTPUT mode */
544 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
545 IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
546 if( !NT_SUCCESS( Status ) )
547 {
548 DbgPrint( "CSR: Failed to set console mode\n" );
549 return;
550 }
551
552 /* blast out buffer */
553 BytesPerLine = CsrpRectWidth(Region) * 2;
554 SrcOffset = (Region.Top * ScreenBuffer->MaxX + Region.Left) * 2;
555 SrcDelta = ScreenBuffer->MaxX * 2;
556 for( i = Region.Top - ScreenBuffer->ShowY, y = ScreenBuffer->ShowY;
557 i <= Region.Bottom - ScreenBuffer->ShowY; i++ )
558 {
559 /* Position the cursor correctly */
560 Status = CsrpSetConsoleDeviceCursor(ScreenBuffer, Region.Left - ScreenBuffer->ShowX, i);
561 if( !NT_SUCCESS( Status ) )
562 {
563 DbgPrint( "CSR: Failed to set console info\n" );
564 return;
565 }
566
567 Status = NtWriteFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
568 &ScreenBuffer->Buffer[ SrcOffset ],
569 BytesPerLine, 0, 0 );
570 if( !NT_SUCCESS( Status ) )
571 {
572 DbgPrint( "CSR: Write to console failed\n" );
573 return;
574 }
575
576 /* wrap back around the end of the buffer */
577 if( ++y == ScreenBuffer->MaxY )
578 y = 0;
579
580 SrcOffset += SrcDelta;
581 }
582 Mode.dwMode = ENABLE_PROCESSED_OUTPUT;
583 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
584 IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
585 if( !NT_SUCCESS( Status ) )
586 {
587 DbgPrint( "CSR: Failed to set console mode\n" );
588 return;
589 }
590 Status = CsrpSetConsoleDeviceCursor(
591 ScreenBuffer,
592 ScreenBuffer->CurrentX - ScreenBuffer->ShowX,
593 ((ScreenBuffer->CurrentY + ScreenBuffer->MaxY) - ScreenBuffer->ShowY) % ScreenBuffer->MaxY);
594 if( !NT_SUCCESS( Status ) )
595 {
596 DbgPrint( "CSR: Failed to set console info\n" );
597 return;
598 }
599 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
600 IOCTL_CONSOLE_SET_CURSOR_INFO, &ScreenBuffer->CursorInfo,
601 sizeof( ScreenBuffer->CursorInfo ), 0, 0 );
602 if( !NT_SUCCESS( Status ) )
603 {
604 DbgPrint( "CSR: Failed to set cursor info\n" );
605 return;
606 }
607 }
608
609
610 CSR_API(CsrWriteConsole)
611 {
612 BYTE *Buffer = Request->Data.WriteConsoleRequest.Buffer;
613 PCSRSS_SCREEN_BUFFER Buff;
614
615 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
616 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
617 sizeof(LPC_MESSAGE_HEADER);
618
619 LOCK;
620 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle,
621 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
622 {
623 UNLOCK;
624 return Reply->Status = STATUS_INVALID_HANDLE;
625 }
626 CsrpWriteConsole( Buff, Buffer, Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE );
627 UNLOCK;
628 return Reply->Status = STATUS_SUCCESS;
629 }
630
631
632 NTSTATUS STDCALL CsrInitConsoleScreenBuffer( PCSRSS_SCREEN_BUFFER Console )
633 {
634 Console->Header.Type = CSRSS_SCREEN_BUFFER_MAGIC;
635 Console->Header.ReferenceCount = 0;
636 Console->MaxX = PhysicalConsoleSize.X;
637 Console->MaxY = PhysicalConsoleSize.Y * 2;
638 Console->ShowX = 0;
639 Console->ShowY = 0;
640 Console->CurrentX = 0;
641 Console->CurrentY = 0;
642 Console->Buffer = RtlAllocateHeap( CsrssApiHeap, 0, Console->MaxX * Console->MaxY * 2 );
643 if( Console->Buffer == 0 )
644 return STATUS_INSUFFICIENT_RESOURCES;
645 Console->DefaultAttrib = 0x17;
646 /* initialize buffer to be empty with default attributes */
647 for( ; Console->CurrentY < Console->MaxY; Console->CurrentY++ )
648 {
649 ClearLineBuffer (Console, 0);
650 }
651 Console->CursorInfo.bVisible = TRUE;
652 Console->CursorInfo.dwSize = 5;
653 Console->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
654 Console->CurrentX = 0;
655 Console->CurrentY = 0;
656 return STATUS_SUCCESS;
657 }
658
659 VOID STDCALL CsrDeleteScreenBuffer( PCSRSS_SCREEN_BUFFER Buffer )
660 {
661 RtlFreeHeap( CsrssApiHeap, 0, Buffer->Buffer );
662 RtlFreeHeap( CsrssApiHeap, 0, Buffer );
663 }
664
665 NTSTATUS STDCALL CsrInitConsole(PCSRSS_CONSOLE Console)
666 {
667 NTSTATUS Status;
668 OBJECT_ATTRIBUTES ObjectAttributes;
669
670 Console->Title.MaximumLength = Console->Title.Length = 0;
671 Console->Title.Buffer = 0;
672
673 RtlCreateUnicodeString( &Console->Title, L"Command Prompt" );
674
675 Console->Header.ReferenceCount = 0;
676 Console->WaitingChars = 0;
677 Console->WaitingLines = 0;
678 Console->EchoCount = 0;
679 Console->Header.Type = CSRSS_CONSOLE_MAGIC;
680 Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
681 Console->EarlyReturn = FALSE;
682 InitializeListHead(&Console->InputEvents);
683
684 InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_INHERIT, NULL, NULL);
685
686 Status = NtCreateEvent( &Console->ActiveEvent, STANDARD_RIGHTS_ALL, &ObjectAttributes, FALSE, FALSE );
687 if( !NT_SUCCESS( Status ) )
688 {
689 return Status;
690 }
691 Console->ActiveBuffer = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
692 if( !Console->ActiveBuffer )
693 {
694 NtClose( Console->ActiveEvent );
695 return STATUS_INSUFFICIENT_RESOURCES;
696 }
697 Status = CsrInitConsoleScreenBuffer( Console->ActiveBuffer );
698 if( !NT_SUCCESS( Status ) )
699 {
700 NtClose( Console->ActiveEvent );
701 RtlFreeHeap( CsrssApiHeap, 0, Console->ActiveBuffer );
702 return Status;
703 }
704 /* add a reference count because the buffer is tied to the console */
705 Console->ActiveBuffer->Header.ReferenceCount++;
706 /* make console active, and insert into console list */
707 LOCK;
708 if( ActiveConsole )
709 {
710 Console->Prev = ActiveConsole;
711 Console->Next = ActiveConsole->Next;
712 ActiveConsole->Next->Prev = Console;
713 ActiveConsole->Next = Console;
714 }
715 else {
716 Console->Prev = Console;
717 Console->Next = Console;
718 }
719 ActiveConsole = Console;
720 /* copy buffer contents to screen */
721 CsrDrawConsole( Console->ActiveBuffer );
722 UNLOCK;
723 return STATUS_SUCCESS;
724 }
725
726 /***************************************************************
727 * CsrDrawConsole blasts the console buffer onto the screen *
728 * must be called while holding the active console lock *
729 **************************************************************/
730 VOID STDCALL CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff )
731 {
732 SMALL_RECT Region;
733
734 CsrpInitRect(
735 Region,
736 Buff->ShowY,
737 Buff->ShowX,
738 Buff->ShowY + PhysicalConsoleSize.Y - 1,
739 Buff->ShowX + PhysicalConsoleSize.X - 1);
740
741 CsrpDrawRegion(Buff, Region);
742 }
743
744
745 VOID STDCALL CsrDeleteConsole( PCSRSS_CONSOLE Console )
746 {
747 ConsoleInput *Event;
748 DPRINT( "CsrDeleteConsole\n" );
749 LOCK;
750 /* Drain input event queue */
751 while( Console->InputEvents.Flink != &Console->InputEvents )
752 {
753 Event = (ConsoleInput *)Console->InputEvents.Flink;
754 Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
755 Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
756 RtlFreeHeap( CsrssApiHeap, 0, Event );
757 }
758 /* Switch to next console */
759 if( ActiveConsole == Console )
760 {
761 if( Console->Next != Console )
762 {
763 ActiveConsole = Console->Next;
764 Console->Prev->Next = Console->Next;
765 Console->Next->Prev = Console->Prev;
766 }
767 else ActiveConsole = 0;
768 }
769 if( ActiveConsole )
770 CsrDrawConsole( ActiveConsole->ActiveBuffer );
771 UNLOCK;
772 if( !--Console->ActiveBuffer->Header.ReferenceCount )
773 CsrDeleteScreenBuffer( Console->ActiveBuffer );
774 NtClose( Console->ActiveEvent );
775 RtlFreeUnicodeString( &Console->Title );
776 RtlFreeHeap( CsrssApiHeap, 0, Console );
777 }
778
779 VOID STDCALL CsrInitConsoleSupport(VOID)
780 {
781 OBJECT_ATTRIBUTES ObjectAttributes;
782 UNICODE_STRING DeviceName;
783 NTSTATUS Status;
784 IO_STATUS_BLOCK Iosb;
785 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
786
787 DPRINT("CSR: CsrInitConsoleSupport()\n");
788
789 RtlInitUnicodeString(&DeviceName, L"\\??\\BlueScreen");
790 InitializeObjectAttributes(&ObjectAttributes,
791 &DeviceName,
792 0,
793 NULL,
794 NULL);
795 Status = NtOpenFile(&ConsoleDeviceHandle,
796 FILE_ALL_ACCESS,
797 &ObjectAttributes,
798 &Iosb,
799 0,
800 FILE_SYNCHRONOUS_IO_ALERT);
801 if (!NT_SUCCESS(Status))
802 {
803 DbgPrint("CSR: Failed to open console. Expect problems.\n");
804 }
805
806 RtlInitUnicodeString(&DeviceName, L"\\??\\Keyboard");
807 InitializeObjectAttributes(&ObjectAttributes,
808 &DeviceName,
809 0,
810 NULL,
811 NULL);
812 Status = NtOpenFile(&KeyboardDeviceHandle,
813 FILE_ALL_ACCESS,
814 &ObjectAttributes,
815 &Iosb,
816 0,
817 0);
818 if (!NT_SUCCESS(Status))
819 {
820 DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
821 }
822
823 ActiveConsole = 0;
824 RtlInitializeCriticalSection( &ActiveConsoleLock );
825 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, &ScrInfo, sizeof( ScrInfo ) );
826 if( !NT_SUCCESS( Status ) )
827 {
828 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
829 return;
830 }
831 PhysicalConsoleSize = ScrInfo.dwSize;
832 }
833
834 VOID Console_Api( DWORD RefreshEvent )
835 {
836 /* keep reading events from the keyboard and stuffing them into the current
837 console's input queue */
838 ConsoleInput *KeyEventRecord;
839 ConsoleInput *TempInput;
840 IO_STATUS_BLOCK Iosb;
841 NTSTATUS Status;
842 HANDLE Events[2]; // 0 = keyboard, 1 = refresh
843 int c;
844 int updown;
845 PCSRSS_CONSOLE SwapConsole = 0; // console we are thinking about swapping with
846
847 Events[0] = 0;
848 Status = NtCreateEvent( &Events[0], STANDARD_RIGHTS_ALL, NULL, FALSE, FALSE );
849 if( !NT_SUCCESS( Status ) )
850 {
851 DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status );
852 NtTerminateProcess( NtCurrentProcess(), Status );
853 }
854 Events[1] = (HANDLE)RefreshEvent;
855 while( 1 )
856 {
857 KeyEventRecord = RtlAllocateHeap(CsrssApiHeap,
858 0,
859 sizeof(ConsoleInput));
860 if ( KeyEventRecord == 0 )
861 {
862 DbgPrint( "CSR: Memory allocation failure!" );
863 continue;
864 }
865 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
866 Status = NtReadFile( KeyboardDeviceHandle, Events[0], NULL, NULL, &Iosb,
867 &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 );
868 if( !NT_SUCCESS( Status ) )
869 {
870 DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
871 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
872 continue;
873 }
874 if( Status == STATUS_PENDING )
875 {
876 while( 1 )
877 {
878 Status = NtWaitForMultipleObjects( 2, Events, WaitAny, FALSE, NULL );
879 if( Status == STATUS_WAIT_0 + 1 )
880 {
881 LOCK;
882 CsrDrawConsole( ActiveConsole->ActiveBuffer );
883 UNLOCK;
884 continue;
885 }
886 else if( Status != STATUS_WAIT_0 )
887 {
888 DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status );
889 NtTerminateProcess( NtCurrentProcess(), Status );
890 }
891 else break;
892 }
893 }
894 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
895 ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED )&&
896 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_TAB )
897 if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
898 {
899 ANSI_STRING Title;
900 void * Buffer;
901 COORD *pos;
902 unsigned int src, dst;
903
904 /* alt-tab, swap consoles */
905 // move SwapConsole to next console, and print its title
906 LOCK;
907 if( !SwapConsole )
908 SwapConsole = ActiveConsole;
909
910 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED )
911 SwapConsole = SwapConsole->Prev;
912 else SwapConsole = SwapConsole->Next;
913 Title.MaximumLength = RtlUnicodeStringToAnsiSize( &SwapConsole->Title );
914 Title.Length = 0;
915 Buffer = RtlAllocateHeap( CsrssApiHeap,
916 0,
917 sizeof( COORD ) + Title.MaximumLength );
918 pos = (COORD *)Buffer;
919 Title.Buffer = Buffer + sizeof( COORD );
920
921 /* this does not seem to work
922 RtlUnicodeStringToAnsiString( &Title, &SwapConsole->Title, FALSE ); */
923 // temp hack
924 for( src = 0, dst = 0; src < SwapConsole->Title.Length; src++, dst++ )
925 Title.Buffer[dst] = (char)SwapConsole->Title.Buffer[dst];
926
927 pos->Y = PhysicalConsoleSize.Y / 2;
928 pos->X = ( PhysicalConsoleSize.X - Title.MaximumLength ) / 2;
929 // redraw the console to clear off old title
930 CsrDrawConsole( ActiveConsole->ActiveBuffer );
931 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
932 NULL,
933 NULL,
934 NULL,
935 &Iosb,
936 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
937 0,
938 0,
939 Buffer,
940 sizeof (COORD) + Title.MaximumLength );
941 if( !NT_SUCCESS( Status ) )
942 {
943 DPRINT1( "Error writing to console\n" );
944 }
945 RtlFreeHeap( CsrssApiHeap, 0, Buffer );
946
947 UNLOCK;
948 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
949 continue;
950 }
951 else {
952 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
953 continue;
954 }
955 else if( SwapConsole &&
956 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_MENU &&
957 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == FALSE )
958 {
959 // alt key released, swap consoles
960 PCSRSS_CONSOLE tmp;
961
962 LOCK;
963 if( SwapConsole != ActiveConsole )
964 {
965 // first remove swapconsole from the list
966 SwapConsole->Prev->Next = SwapConsole->Next;
967 SwapConsole->Next->Prev = SwapConsole->Prev;
968 // now insert before activeconsole
969 SwapConsole->Next = ActiveConsole;
970 SwapConsole->Prev = ActiveConsole->Prev;
971 ActiveConsole->Prev->Next = SwapConsole;
972 ActiveConsole->Prev = SwapConsole;
973 }
974 ActiveConsole = SwapConsole;
975 SwapConsole = 0;
976 CsrDrawConsole( ActiveConsole->ActiveBuffer );
977
978 UNLOCK;
979 }
980 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
981 ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) &&
982 ( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP ||
983 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) )
984 {
985 if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
986 {
987 /* scroll up or down */
988 LOCK;
989 if( ActiveConsole == 0 )
990 {
991 DbgPrint( "CSR: No Active Console!\n" );
992 UNLOCK;
993 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
994 continue;
995 }
996 if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP )
997 {
998 /* only scroll up if there is room to scroll up into */
999 if( ActiveConsole->ActiveBuffer->ShowY != ((ActiveConsole->ActiveBuffer->CurrentY + 1) %
1000 ActiveConsole->ActiveBuffer->MaxY) )
1001 ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY +
1002 ActiveConsole->ActiveBuffer->MaxY - 1) % ActiveConsole->ActiveBuffer->MaxY;
1003 }
1004 else if( ActiveConsole->ActiveBuffer->ShowY != ActiveConsole->ActiveBuffer->CurrentY )
1005 /* only scroll down if there is room to scroll down into */
1006 if( ActiveConsole->ActiveBuffer->ShowY % ActiveConsole->ActiveBuffer->MaxY !=
1007 ActiveConsole->ActiveBuffer->CurrentY )
1008
1009 if( ((ActiveConsole->ActiveBuffer->CurrentY + 1) % ActiveConsole->ActiveBuffer->MaxY) !=
1010 (ActiveConsole->ActiveBuffer->ShowY + PhysicalConsoleSize.Y) % ActiveConsole->ActiveBuffer->MaxY )
1011 ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY + 1) %
1012 ActiveConsole->ActiveBuffer->MaxY;
1013 CsrDrawConsole( ActiveConsole->ActiveBuffer );
1014 UNLOCK;
1015 }
1016 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1017 continue;
1018 }
1019 LOCK;
1020 if( ActiveConsole == 0 )
1021 {
1022 DbgPrint( "CSR: No Active Console!\n" );
1023 UNLOCK;
1024 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1025 continue;
1026 }
1027 // process special keys if enabled
1028 if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) )
1029 switch( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar )
1030 {
1031 case '\r':
1032 // add a \n to the queue as well
1033 // first add the \r
1034 updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
1035 KeyEventRecord->Echoed = FALSE;
1036 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
1037 InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1038 ActiveConsole->WaitingChars++;
1039 KeyEventRecord = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( ConsoleInput ) );
1040 if( !KeyEventRecord )
1041 {
1042 DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
1043 UNLOCK;
1044 continue;
1045 }
1046 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1047 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
1048 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
1049 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
1050 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
1051 }
1052 // add event to the queue
1053 InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1054 // if line input mode is enabled, only wake the client on enter key down
1055 if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT ) ||
1056 ActiveConsole->EarlyReturn ||
1057 ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' &&
1058 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) )
1059 {
1060 NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1061 if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1062 ActiveConsole->WaitingLines++;
1063 }
1064 KeyEventRecord->Echoed = FALSE;
1065 if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) &&
1066 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' &&
1067 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown )
1068 {
1069 // walk the input queue looking for a char to backspace
1070 for( TempInput = (ConsoleInput *)ActiveConsole->InputEvents.Blink;
1071 TempInput != (ConsoleInput *)&ActiveConsole->InputEvents &&
1072 (TempInput->InputEvent.EventType != KEY_EVENT ||
1073 TempInput->InputEvent.Event.KeyEvent.bKeyDown == FALSE ||
1074 TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' );
1075 TempInput = (ConsoleInput *)TempInput->ListEntry.Blink );
1076 // if we found one, delete it, otherwise, wake the client
1077 if( TempInput != (ConsoleInput *)&ActiveConsole->InputEvents )
1078 {
1079 // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
1080 RemoveEntryList(&TempInput->ListEntry);
1081 if( TempInput->Echoed )
1082 CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1083 RtlFreeHeap( CsrssApiHeap, 0, TempInput );
1084 RemoveEntryList(&KeyEventRecord->ListEntry);
1085 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1086 ActiveConsole->WaitingChars -= 2;
1087 }
1088 else NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1089 }
1090 else {
1091 // echo chars if we are supposed to and client is waiting for some
1092 if( ( ActiveConsole->Mode & ENABLE_ECHO_INPUT ) && ActiveConsole->EchoCount &&
1093 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar &&
1094 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE &&
1095 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
1096 {
1097 // mark the char as already echoed
1098 CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1099 ActiveConsole->EchoCount--;
1100 KeyEventRecord->Echoed = TRUE;
1101 }
1102 }
1103 ActiveConsole->WaitingChars++;
1104 if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT) )
1105 NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1106 UNLOCK;
1107 }
1108 }
1109
1110 CSR_API(CsrGetScreenBufferInfo)
1111 {
1112 NTSTATUS Status;
1113 PCSRSS_SCREEN_BUFFER Buff;
1114 PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1115 IO_STATUS_BLOCK Iosb;
1116
1117 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1118 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1119 sizeof(LPC_MESSAGE_HEADER);
1120
1121 LOCK;
1122 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle,
1123 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1124 {
1125 UNLOCK;
1126 return Reply->Status = STATUS_INVALID_HANDLE;
1127 }
1128 pInfo = &Reply->Data.ScreenBufferInfoReply.Info;
1129 if( Buff == ActiveConsole->ActiveBuffer )
1130 {
1131 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1132 IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, pInfo, sizeof( *pInfo ) );
1133 if( !NT_SUCCESS( Status ) )
1134 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
1135 Reply->Status = Status;
1136 }
1137 else {
1138 pInfo->dwSize.X = PhysicalConsoleSize.X;
1139 pInfo->dwSize.Y = PhysicalConsoleSize.Y;
1140 pInfo->dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1141 pInfo->dwCursorPosition.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1142 pInfo->wAttributes = Buff->DefaultAttrib;
1143 pInfo->srWindow.Left = 0;
1144 pInfo->srWindow.Right = PhysicalConsoleSize.X - 1;
1145 pInfo->srWindow.Top = 0;
1146 pInfo->srWindow.Bottom = PhysicalConsoleSize.Y - 1;
1147 Reply->Status = STATUS_SUCCESS;
1148 }
1149 UNLOCK;
1150 return Reply->Status;
1151 }
1152
1153 CSR_API(CsrSetCursor)
1154 {
1155 NTSTATUS Status;
1156 PCSRSS_SCREEN_BUFFER Buff;
1157 CONSOLE_SCREEN_BUFFER_INFO Info;
1158 IO_STATUS_BLOCK Iosb;
1159
1160 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1161 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1162 sizeof(LPC_MESSAGE_HEADER);
1163
1164 LOCK;
1165 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.SetCursorRequest.ConsoleHandle,
1166 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1167 {
1168 UNLOCK;
1169 return Reply->Status = STATUS_INVALID_HANDLE;
1170 }
1171 Info.dwCursorPosition = Request->Data.SetCursorRequest.Position;
1172 Info.wAttributes = Buff->DefaultAttrib;
1173 if( Buff == ActiveConsole->ActiveBuffer )
1174 {
1175 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1176 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &Info, sizeof( Info ), 0, 0 );
1177 if( !NT_SUCCESS( Status ) )
1178 DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
1179 }
1180
1181 Buff->CurrentX = Info.dwCursorPosition.X + Buff->ShowX;
1182 Buff->CurrentY = (Info.dwCursorPosition.Y + Buff->ShowY) % Buff->MaxY;
1183 UNLOCK;
1184 return Reply->Status = Status;
1185 }
1186
1187 CSR_API(CsrWriteConsoleOutputChar)
1188 {
1189 BYTE *Buffer = Request->Data.WriteConsoleOutputCharRequest.String;
1190 PCSRSS_SCREEN_BUFFER Buff;
1191 DWORD X, Y;
1192 NTSTATUS Status;
1193 IO_STATUS_BLOCK Iosb;
1194
1195 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1196 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1197 sizeof(LPC_MESSAGE_HEADER);
1198 LOCK;
1199 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1200 {
1201 UNLOCK;
1202 return Reply->Status = STATUS_INVALID_HANDLE;
1203 }
1204 X = Buff->CurrentX;
1205 Y = Buff->CurrentY;
1206 Buff->CurrentX = Request->Data.WriteConsoleOutputCharRequest.Coord.X;
1207 Buff->CurrentY = Request->Data.WriteConsoleOutputCharRequest.Coord.Y;
1208 Buffer[Request->Data.WriteConsoleOutputCharRequest.Length] = 0;
1209 CsrpWriteConsole( Buff, Buffer, Request->Data.WriteConsoleOutputCharRequest.Length, FALSE );
1210 if( ActiveConsole->ActiveBuffer == Buff )
1211 {
1212 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1213 NULL,
1214 NULL,
1215 NULL,
1216 &Iosb,
1217 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
1218 0,
1219 0,
1220 &Request->Data.WriteConsoleOutputCharRequest.Coord,
1221 sizeof (COORD) + Request->Data.WriteConsoleOutputCharRequest.Length );
1222 if( !NT_SUCCESS( Status ) )
1223 DPRINT1( "Failed to write output chars: %x\n", Status );
1224 }
1225 Reply->Data.WriteConsoleOutputCharReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1226 Reply->Data.WriteConsoleOutputCharReply.EndCoord.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1227 Buff->CurrentY = Y;
1228 Buff->CurrentX = X;
1229 UNLOCK;
1230 return Reply->Status = STATUS_SUCCESS;
1231 }
1232
1233 CSR_API(CsrFillOutputChar)
1234 {
1235 PCSRSS_SCREEN_BUFFER Buff;
1236 DWORD X, Y, i;
1237
1238 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1239 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1240 sizeof(LPC_MESSAGE_HEADER);
1241
1242 LOCK;
1243 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1244 {
1245 UNLOCK;
1246 return Reply->Status = STATUS_INVALID_HANDLE;
1247 }
1248 X = Request->Data.FillOutputRequest.Position.X + Buff->ShowX;
1249 Y = Request->Data.FillOutputRequest.Position.Y + Buff->ShowY;
1250 for( i = 0; i < 20000; i++ );
1251 for( i = 0; i < Request->Data.FillOutputRequest.Length; i++ )
1252 {
1253 Buff->Buffer[ (Y * 2 * Buff->MaxX) + (X * 2) ] = Request->Data.FillOutputRequest.Char;
1254 if( ++X == Buff->MaxX )
1255 {
1256 if( ++Y == Buff->MaxY )
1257 Y = 0;
1258 X = 0;
1259 }
1260 }
1261 if( Buff == ActiveConsole->ActiveBuffer )
1262 CsrDrawConsole( Buff );
1263 UNLOCK;
1264 return Reply->Status;
1265 }
1266
1267 CSR_API(CsrReadInputEvent)
1268 {
1269 PLIST_ENTRY CurrentEntry;
1270 PCSRSS_CONSOLE Console;
1271 NTSTATUS Status;
1272 ConsoleInput *Input;
1273
1274 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1275 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1276 sizeof(LPC_MESSAGE_HEADER);
1277 Reply->Data.ReadInputReply.Event = ProcessData->ConsoleEvent;
1278
1279 LOCK;
1280 Status = CsrGetObject( ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, (Object_t **)&Console );
1281 if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? 0 : STATUS_INVALID_HANDLE))
1282 {
1283 Reply->Status = Status;
1284 UNLOCK;
1285 return Status;
1286 }
1287
1288 // only get input if there is any
1289 if( Console->InputEvents.Flink != &Console->InputEvents )
1290 {
1291 CurrentEntry = RemoveHeadList(&Console->InputEvents);
1292 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1293 Reply->Data.ReadInputReply.Input = Input->InputEvent;
1294
1295 if( Input->InputEvent.EventType == KEY_EVENT )
1296 {
1297 if( Console->Mode & ENABLE_LINE_INPUT &&
1298 Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE &&
1299 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1300 Console->WaitingLines--;
1301 Console->WaitingChars--;
1302 }
1303 RtlFreeHeap( CsrssApiHeap, 0, Input );
1304 Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents) ? TRUE : FALSE;
1305 Status = STATUS_SUCCESS;
1306 Console->EarlyReturn = FALSE; // clear early return
1307 }
1308 else {
1309 Status = STATUS_PENDING;
1310 Console->EarlyReturn = TRUE; // mark for early return
1311 }
1312 UNLOCK;
1313 return Reply->Status = Status;
1314 }
1315
1316 CSR_API(CsrWriteConsoleOutputAttrib)
1317 {
1318 int c;
1319 PCSRSS_SCREEN_BUFFER Buff;
1320 NTSTATUS Status;
1321 int X, Y;
1322 IO_STATUS_BLOCK Iosb;
1323
1324 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1325 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1326 sizeof(LPC_MESSAGE_HEADER);
1327 LOCK;
1328 Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1329 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1330 {
1331 Reply->Status = Status;
1332 UNLOCK;
1333 return Status;
1334 }
1335 X = Buff->CurrentX;
1336 Y = Buff->CurrentY;
1337 Buff->CurrentX = Request->Data.WriteConsoleOutputAttribRequest.Coord.X + Buff->ShowX;
1338 Buff->CurrentY = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1339 for( c = 0; c < Request->Data.WriteConsoleOutputAttribRequest.Length; c++ )
1340 {
1341 Buff->Buffer[(Buff->CurrentY * Buff->MaxX * 2) + (Buff->CurrentX * 2) + 1] = Request->Data.WriteConsoleOutputAttribRequest.String[c];
1342 if( ++Buff->CurrentX == Buff->MaxX )
1343 {
1344 Buff->CurrentX = 0;
1345 if( ++Buff->CurrentY == Buff->MaxY )
1346 Buff->CurrentY = 0;
1347 }
1348 }
1349 if( Buff == ActiveConsole->ActiveBuffer )
1350 {
1351 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1352 NULL,
1353 NULL,
1354 NULL,
1355 &Iosb,
1356 IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE,
1357 0,
1358 0,
1359 &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1360 Request->Data.WriteConsoleOutputAttribRequest.Length +
1361 sizeof (COORD) );
1362 if( !NT_SUCCESS( Status ) )
1363 DPRINT1( "Failed to write output attributes to console\n" );
1364 }
1365 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1366 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.Y = ( Buff->CurrentY + Buff->MaxY - Buff->ShowY ) % Buff->MaxY;
1367 Buff->CurrentX = X;
1368 Buff->CurrentY = Y;
1369 UNLOCK;
1370 return Reply->Status = STATUS_SUCCESS;
1371 }
1372
1373 CSR_API(CsrFillOutputAttrib)
1374 {
1375 int c;
1376 PCSRSS_SCREEN_BUFFER Buff;
1377 NTSTATUS Status;
1378 int X, Y;
1379 IO_STATUS_BLOCK Iosb;
1380 OUTPUT_ATTRIBUTE Attr;
1381
1382 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1383 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1384 sizeof(LPC_MESSAGE_HEADER);
1385 LOCK;
1386 Status = CsrGetObject( ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1387 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1388 {
1389 Reply->Status = Status;
1390 UNLOCK;
1391 return Status;
1392 }
1393 X = Buff->CurrentX;
1394 Y = Buff->CurrentY;
1395 Buff->CurrentX = Request->Data.FillOutputAttribRequest.Coord.X + Buff->ShowX;
1396 Buff->CurrentY = Request->Data.FillOutputAttribRequest.Coord.Y + Buff->ShowY;
1397 for( c = 0; c < Request->Data.FillOutputAttribRequest.Length; c++ )
1398 {
1399 Buff->Buffer[(Buff->CurrentY * Buff->MaxX * 2) + (Buff->CurrentX * 2) + 1] = Request->Data.FillOutputAttribRequest.Attribute;
1400 if( ++Buff->CurrentX == Buff->MaxX )
1401 {
1402 Buff->CurrentX = 0;
1403 if( ++Buff->CurrentY == Buff->MaxY )
1404 Buff->CurrentY = 0;
1405 }
1406 }
1407 if( Buff == ActiveConsole->ActiveBuffer )
1408 {
1409 Attr.wAttribute = Request->Data.FillOutputAttribRequest.Attribute;
1410 Attr.nLength = Request->Data.FillOutputAttribRequest.Length;
1411 Attr.dwCoord = Request->Data.FillOutputAttribRequest.Coord;
1412 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1413 NULL,
1414 NULL,
1415 NULL,
1416 &Iosb,
1417 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE,
1418 &Attr,
1419 sizeof (Attr),
1420 0,
1421 0 );
1422 if( !NT_SUCCESS( Status ) )
1423 DPRINT1( "Failed to fill output attribute\n" );
1424 }
1425 Buff->CurrentX = X;
1426 Buff->CurrentY = Y;
1427 UNLOCK;
1428 return Reply->Status = STATUS_SUCCESS;
1429 }
1430
1431
1432 CSR_API(CsrGetCursorInfo)
1433 {
1434 PCSRSS_SCREEN_BUFFER Buff;
1435 NTSTATUS Status;
1436
1437 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1438 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1439 sizeof(LPC_MESSAGE_HEADER);
1440 LOCK;
1441 Status = CsrGetObject( ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1442 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1443 {
1444 Reply->Status = Status;
1445 UNLOCK;
1446 return Status;
1447 }
1448 Reply->Data.GetCursorInfoReply.Info = Buff->CursorInfo;
1449 UNLOCK;
1450 return Reply->Status = STATUS_SUCCESS;
1451 }
1452
1453 CSR_API(CsrSetCursorInfo)
1454 {
1455 PCSRSS_SCREEN_BUFFER Buff;
1456 NTSTATUS Status;
1457 IO_STATUS_BLOCK Iosb;
1458
1459 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1460 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1461 sizeof(LPC_MESSAGE_HEADER);
1462 LOCK;
1463 Status = CsrGetObject( ProcessData,
1464 Request->Data.SetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1465
1466 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1467 {
1468 Reply->Status = Status;
1469 UNLOCK;
1470 return Status;
1471 }
1472 Buff->CursorInfo = Request->Data.SetCursorInfoRequest.Info;
1473 if( Buff == ActiveConsole->ActiveBuffer )
1474 {
1475 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_CURSOR_INFO, &Buff->CursorInfo, sizeof( Buff->CursorInfo ), 0, 0 );
1476 if( !NT_SUCCESS( Status ) )
1477 {
1478 DbgPrint( "CSR: Failed to set cursor info\n" );
1479 return Reply->Status = Status;
1480 }
1481 }
1482 UNLOCK;
1483 return Reply->Status = STATUS_SUCCESS;
1484 }
1485
1486 CSR_API(CsrSetTextAttrib)
1487 {
1488 NTSTATUS Status;
1489 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
1490 IO_STATUS_BLOCK Iosb;
1491 PCSRSS_SCREEN_BUFFER Buff;
1492
1493 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1494 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1495 sizeof(LPC_MESSAGE_HEADER);
1496 LOCK;
1497 Status = CsrGetObject( ProcessData, Request->Data.SetAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1498 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1499 {
1500 Reply->Status = Status;
1501 UNLOCK;
1502 return Status;
1503 }
1504 Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1505 if( Buff == ActiveConsole->ActiveBuffer )
1506 {
1507 ScrInfo.wAttributes = Buff->DefaultAttrib;
1508 ScrInfo.dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1509 ScrInfo.dwCursorPosition.Y = ((Buff->CurrentY + Buff->MaxY) - Buff->ShowY) % Buff->MaxY;
1510 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
1511 if( !NT_SUCCESS( Status ) )
1512 {
1513 DbgPrint( "CSR: Failed to set console info\n" );
1514 UNLOCK;
1515 return Reply->Status = Status;
1516 }
1517 }
1518 UNLOCK;
1519 return Reply->Status = STATUS_SUCCESS;
1520 }
1521
1522 CSR_API(CsrSetConsoleMode)
1523 {
1524 NTSTATUS Status;
1525 PCSRSS_CONSOLE Console;
1526 PCSRSS_SCREEN_BUFFER Buff;
1527
1528 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1529 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER);
1530 LOCK;
1531 Status = CsrGetObject( ProcessData,
1532 Request->Data.SetConsoleModeRequest.ConsoleHandle,
1533 (Object_t **)&Console );
1534 if( !NT_SUCCESS( Status ) )
1535 {
1536 Reply->Status = Status;
1537 UNLOCK;
1538 return Status;
1539 }
1540
1541 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1542 if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1543 Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1544 else if( Console->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1545 Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1546 else {
1547 Reply->Status = STATUS_INVALID_HANDLE;
1548 UNLOCK;
1549 return Status;
1550 }
1551 UNLOCK;
1552 Reply->Status = STATUS_SUCCESS;
1553 return Reply->Status;
1554 }
1555
1556 CSR_API(CsrGetConsoleMode)
1557 {
1558 NTSTATUS Status;
1559 PCSRSS_CONSOLE Console;
1560 PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
1561
1562 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1563 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER);
1564 LOCK;
1565 Status = CsrGetObject( ProcessData,
1566 Request->Data.GetConsoleModeRequest.ConsoleHandle,
1567 (Object_t **)&Console );
1568 if( !NT_SUCCESS( Status ) )
1569 {
1570 Reply->Status = Status;
1571 UNLOCK;
1572 return Status;
1573 }
1574 Reply->Status = STATUS_SUCCESS;
1575 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1576 if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1577 Reply->Data.GetConsoleModeReply.ConsoleMode = Console->Mode;
1578 else if( Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1579 Reply->Data.GetConsoleModeReply.ConsoleMode = Buff->Mode;
1580 else Status = STATUS_INVALID_HANDLE;
1581 UNLOCK;
1582 return Reply->Status;
1583 }
1584
1585 CSR_API(CsrCreateScreenBuffer)
1586 {
1587 PCSRSS_SCREEN_BUFFER Buff = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
1588 NTSTATUS Status;
1589
1590 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1591 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER);
1592 if( !Buff )
1593 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
1594 LOCK;
1595 Status = CsrInitConsoleScreenBuffer( Buff );
1596 if( !NT_SUCCESS( Status ) )
1597 Reply->Status = Status;
1598 else {
1599 Status = CsrInsertObject( ProcessData, &Reply->Data.CreateScreenBufferReply.OutputHandle, &Buff->Header );
1600 if( !NT_SUCCESS( Status ) )
1601 Reply->Status = Status;
1602 else Reply->Status = STATUS_SUCCESS;
1603 }
1604 UNLOCK;
1605 return Reply->Status;
1606 }
1607
1608 CSR_API(CsrSetScreenBuffer)
1609 {
1610 NTSTATUS Status;
1611 PCSRSS_SCREEN_BUFFER Buff;
1612
1613 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1614 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER);
1615 LOCK;
1616 Status = CsrGetObject( ProcessData, Request->Data.SetActiveScreenBufferRequest.OutputHandle, (Object_t **)&Buff );
1617 if( !NT_SUCCESS( Status ) )
1618 Reply->Status = Status;
1619 else {
1620 // drop reference to old buffer, maybe delete
1621 if( !InterlockedDecrement( &ProcessData->Console->ActiveBuffer->Header.ReferenceCount ) )
1622 CsrDeleteScreenBuffer( ProcessData->Console->ActiveBuffer );
1623 // tie console to new buffer
1624 ProcessData->Console->ActiveBuffer = Buff;
1625 // inc ref count on new buffer
1626 InterlockedIncrement( &Buff->Header.ReferenceCount );
1627 // if the console is active, redraw it
1628 if( ActiveConsole == ProcessData->Console )
1629 CsrDrawConsole( Buff );
1630 Reply->Status = STATUS_SUCCESS;
1631 }
1632 UNLOCK;
1633 return Reply->Status;
1634 }
1635
1636 CSR_API(CsrSetTitle)
1637 {
1638 NTSTATUS Status;
1639 PCSRSS_CONSOLE Console;
1640
1641 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1642 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER);
1643 LOCK;
1644 Status = CsrGetObject( ProcessData, Request->Data.SetTitleRequest.Console, (Object_t **)&Console );
1645 if( !NT_SUCCESS( Status ) )
1646 Reply->Status = Status;
1647 else {
1648 // copy title to console
1649 RtlFreeUnicodeString( &Console->Title );
1650 RtlCreateUnicodeString( &Console->Title, Request->Data.SetTitleRequest.Title );
1651 Reply->Status = STATUS_SUCCESS;
1652 }
1653 UNLOCK;
1654 return Reply->Status;
1655 }
1656
1657 CSR_API(CsrGetTitle)
1658 {
1659 NTSTATUS Status;
1660 PCSRSS_CONSOLE Console;
1661
1662 Reply->Header.MessageSize = sizeof (CSRSS_API_REPLY);
1663 Reply->Header.DataSize =
1664 sizeof (CSRSS_API_REPLY)
1665 - sizeof(LPC_MESSAGE_HEADER);
1666 LOCK;
1667 Status = CsrGetObject (
1668 ProcessData,
1669 Request->Data.GetTitleRequest.ConsoleHandle,
1670 (Object_t **) & Console
1671 );
1672 if ( !NT_SUCCESS( Status ) )
1673 {
1674 Reply->Status = Status;
1675 }
1676 else
1677 {
1678 HANDLE ConsoleHandle = Request->Data.GetTitleRequest.ConsoleHandle;
1679
1680 /* Copy title of the console to the user title buffer */
1681 RtlZeroMemory (
1682 & Reply->Data.GetTitleReply,
1683 sizeof (CSRSS_GET_TITLE_REPLY)
1684 );
1685 Reply->Data.GetTitleReply.ConsoleHandle = ConsoleHandle;
1686 Reply->Data.GetTitleReply.Length = Console->Title.Length;
1687 wcscpy (Reply->Data.GetTitleReply.Title, Console->Title.Buffer);
1688 Reply->Status = STATUS_SUCCESS;
1689 }
1690 UNLOCK;
1691 return Reply->Status;
1692 }
1693
1694 CSR_API(CsrWriteConsoleOutput)
1695 {
1696 SHORT i, X, Y, SizeX, SizeY;
1697 PCSRSS_SCREEN_BUFFER Buff;
1698 SMALL_RECT ScreenBuffer;
1699 CHAR_INFO* CurCharInfo;
1700 SMALL_RECT WriteRegion;
1701 CHAR_INFO* CharInfo;
1702 COORD BufferCoord;
1703 COORD BufferSize;
1704 NTSTATUS Status;
1705 DWORD Offset;
1706 DWORD PSize;
1707
1708 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1709 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER);
1710 LOCK;
1711 Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputRequest.ConsoleHandle, (Object_t **)&Buff );
1712 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1713 {
1714 Reply->Status = Status;
1715 UNLOCK;
1716 return Status;
1717 }
1718
1719 BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
1720 PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
1721 BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
1722 CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
1723 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
1724 (((PVOID)CharInfo + PSize) >
1725 (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
1726 {
1727 UNLOCK;
1728 Reply->Status = STATUS_ACCESS_VIOLATION;
1729 return(Reply->Status);
1730 }
1731 WriteRegion = Request->Data.WriteConsoleOutputRequest.WriteRegion;
1732
1733 SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(WriteRegion));
1734 SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(WriteRegion));
1735 WriteRegion.Bottom = WriteRegion.Top + SizeY;
1736 WriteRegion.Right = WriteRegion.Left + SizeX;
1737
1738 /* Make sure WriteRegion is inside the screen buffer */
1739 CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1740 if (!CsrpGetIntersection(&WriteRegion, ScreenBuffer, WriteRegion))
1741 {
1742 UNLOCK;
1743 /* It is okay to have a WriteRegion completely outside the screen buffer.
1744 No data is written then. */
1745 return (Reply->Status = STATUS_SUCCESS);
1746 }
1747
1748 for ( i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++ )
1749 {
1750 CurCharInfo = CharInfo + (i * BufferSize.Y);
1751 Offset = (Y * Buff->MaxX + WriteRegion.Left) * 2;
1752 for ( X = WriteRegion.Left; X <= WriteRegion.Right; X++ )
1753 {
1754 SET_CELL_BUFFER(Buff, Offset, CurCharInfo->Char.AsciiChar, CurCharInfo->Attributes);
1755 CurCharInfo++;
1756 }
1757 }
1758
1759 if( Buff == ActiveConsole->ActiveBuffer )
1760 {
1761 CsrpDrawRegion( ActiveConsole->ActiveBuffer, WriteRegion );
1762 }
1763
1764 UNLOCK;
1765 Reply->Data.WriteConsoleOutputReply.WriteRegion.Right = WriteRegion.Left + SizeX - 1;
1766 Reply->Data.WriteConsoleOutputReply.WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
1767 return (Reply->Status = STATUS_SUCCESS);
1768 }
1769
1770 CSR_API(CsrFlushInputBuffer)
1771 {
1772 PLIST_ENTRY CurrentEntry;
1773 PLIST_ENTRY NextEntry;
1774 PCSRSS_CONSOLE Console;
1775 ConsoleInput* Input;
1776 NTSTATUS Status;
1777
1778 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1779 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER);
1780 LOCK;
1781 Status = CsrGetObject( ProcessData, Request->Data.FlushInputBufferRequest.ConsoleInput, (Object_t **)&Console );
1782 if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1783 {
1784 Reply->Status = Status;
1785 UNLOCK;
1786 return Status;
1787 }
1788
1789 /* Discard all entries in the input event queue */
1790 CurrentEntry = Console->InputEvents.Flink;
1791 while (IsListEmpty(&Console->InputEvents))
1792 {
1793 NextEntry = CurrentEntry->Flink;
1794 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1795 /* Destroy the event */
1796 Console->WaitingChars--;
1797 RtlFreeHeap( CsrssApiHeap, 0, Input );
1798 CurrentEntry = NextEntry;
1799 }
1800 UNLOCK;
1801
1802 return (Reply->Status = STATUS_SUCCESS);
1803 }
1804
1805 CSR_API(CsrScrollConsoleScreenBuffer)
1806 {
1807 SHORT i, X, Y, SizeX, SizeY;
1808 PCSRSS_SCREEN_BUFFER Buff;
1809 SMALL_RECT ScreenBuffer;
1810 SMALL_RECT SrcRegion;
1811 SMALL_RECT DstRegion;
1812 SMALL_RECT FillRegion;
1813 IO_STATUS_BLOCK Iosb;
1814 CHAR_INFO* CharInfo;
1815 NTSTATUS Status;
1816 DWORD SrcOffset;
1817 DWORD DstOffset;
1818 BOOLEAN DoFill;
1819
1820 ALIAS(ConsoleHandle,Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle);
1821 ALIAS(ScrollRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle);
1822 ALIAS(UseClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle);
1823 ALIAS(ClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle);
1824 ALIAS(DestinationOrigin,Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin);
1825 ALIAS(Fill,Request->Data.ScrollConsoleScreenBufferRequest.Fill);
1826
1827 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1828 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE_HEADER);
1829 LOCK;
1830 Status = CsrGetObject( ProcessData, ConsoleHandle, (Object_t **)&Buff );
1831 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1832 {
1833 Reply->Status = Status;
1834 UNLOCK;
1835 return Status;
1836 }
1837
1838 /* Make sure source rectangle is inside the screen buffer */
1839 CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1840 if (!CsrpGetIntersection(&SrcRegion, ScreenBuffer, ScrollRectangle))
1841 {
1842 UNLOCK;
1843 return (Reply->Status = STATUS_INVALID_PARAMETER);
1844 }
1845
1846 if (UseClipRectangle)
1847 {
1848 if (!CsrpGetIntersection(&SrcRegion, SrcRegion, ClipRectangle))
1849 {
1850 UNLOCK;
1851 return (Reply->Status = STATUS_SUCCESS);
1852 }
1853 }
1854
1855
1856 CsrpInitRect(
1857 DstRegion,
1858 DestinationOrigin.Y,
1859 DestinationOrigin.X,
1860 DestinationOrigin.Y + CsrpRectHeight(ScrollRectangle) - 1,
1861 DestinationOrigin.X + CsrpRectWidth(ScrollRectangle) - 1)
1862
1863 /* Make sure destination rectangle is inside the screen buffer */
1864 if (!CsrpGetIntersection(&DstRegion, DstRegion, ScreenBuffer))
1865 {
1866 UNLOCK;
1867 return (Reply->Status = STATUS_INVALID_PARAMETER);
1868 }
1869
1870 CsrpCopyRegion(Buff, SrcRegion, DstRegion);
1871
1872
1873 /* Get the region that should be filled with the specified character and attributes */
1874
1875 DoFill = FALSE;
1876
1877 CsrpGetUnion(&FillRegion, SrcRegion, DstRegion);
1878
1879 if (CsrpSubtractRect(&FillRegion, FillRegion, DstRegion))
1880 {
1881 /* FIXME: The subtracted rectangle is off by one line */
1882 FillRegion.Top += 1;
1883
1884 CsrpFillRegion(Buff, FillRegion, Fill);
1885 DoFill = TRUE;
1886 }
1887
1888 if( Buff == ActiveConsole->ActiveBuffer )
1889 {
1890 /* Draw destination region */
1891 CsrpDrawRegion(ActiveConsole->ActiveBuffer, DstRegion);
1892
1893 if (DoFill)
1894 {
1895 /* Draw filled region */
1896 CsrpDrawRegion(ActiveConsole->ActiveBuffer, FillRegion);
1897 }
1898 }
1899
1900 UNLOCK;
1901 return (Reply->Status = STATUS_SUCCESS);
1902 }
1903
1904 /* EOF */