update for HEAD-2002110401
[reactos.git] / subsys / csrss / api / conio.c
1 /* $Id$
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);
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);
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);
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);
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    RtlInitUnicodeStringFromLiteral(&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    RtlInitUnicodeStringFromLiteral(&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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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
1905 CSR_API(CsrReadConsoleOutputChar)
1906 {
1907   NTSTATUS Status;
1908   PCSRSS_SCREEN_BUFFER ScreenBuffer;
1909   DWORD Xpos, Ypos;
1910   BYTE* ReadBuffer;
1911   DWORD i;
1912
1913   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1914   Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
1915   ReadBuffer = Reply->Data.ReadConsoleOutputCharReply.String;
1916
1917   LOCK;
1918
1919   Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
1920   if (!NT_SUCCESS(Status))
1921     {
1922       Reply->Status = Status;
1923       UNLOCK;
1924       return(Reply->Status);
1925     }
1926
1927   if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
1928     {
1929       Reply->Status = STATUS_INVALID_HANDLE;
1930       UNLOCK;
1931       return(Reply->Status);
1932     }
1933
1934   Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X + ScreenBuffer->ShowX;
1935   Ypos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + ScreenBuffer->ShowY;
1936
1937   for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
1938     {
1939       *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX)];
1940
1941       ReadBuffer++;
1942       Xpos++;
1943
1944       if (Xpos == ScreenBuffer->MaxX)
1945         {
1946           Xpos = 0;
1947           Ypos++;
1948
1949           if (Ypos == ScreenBuffer->MaxY)
1950             Ypos = 0;
1951         }
1952     }
1953
1954   *ReadBuffer = 0;
1955
1956   Reply->Status = STATUS_SUCCESS;
1957   Reply->Data.ReadConsoleOutputCharReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
1958   Reply->Data.ReadConsoleOutputCharReply.EndCoord.Y = Ypos - ScreenBuffer->ShowY;
1959   Reply->Header.MessageSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
1960   Reply->Header.DataSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
1961
1962   UNLOCK;
1963
1964   return(Reply->Status);
1965 }
1966
1967
1968 CSR_API(CsrReadConsoleOutputAttrib)
1969 {
1970   NTSTATUS Status;
1971   PCSRSS_SCREEN_BUFFER ScreenBuffer;
1972   DWORD Xpos, Ypos;
1973   CHAR* ReadBuffer;
1974   DWORD i;
1975
1976   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1977   Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
1978   ReadBuffer = Reply->Data.ReadConsoleOutputAttribReply.String;
1979
1980   LOCK;
1981
1982   Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
1983   if (!NT_SUCCESS(Status))
1984     {
1985       Reply->Status = Status;
1986       UNLOCK;
1987       return(Reply->Status);
1988     }
1989
1990   if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
1991     {
1992       Reply->Status = STATUS_INVALID_HANDLE;
1993       UNLOCK;
1994       return(Reply->Status);
1995     }
1996
1997   Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X + ScreenBuffer->ShowX;
1998   Ypos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + ScreenBuffer->ShowY;
1999
2000   for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2001     {
2002       *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX) + 1];
2003
2004       ReadBuffer++;
2005       Xpos++;
2006
2007       if (Xpos == ScreenBuffer->MaxX)
2008         {
2009           Xpos = 0;
2010           Ypos++;
2011
2012           if (Ypos == ScreenBuffer->MaxY)
2013             Ypos = 0;
2014         }
2015     }
2016
2017   *ReadBuffer = 0;
2018
2019   Reply->Status = STATUS_SUCCESS;
2020   Reply->Data.ReadConsoleOutputAttribReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
2021   Reply->Data.ReadConsoleOutputAttribReply.EndCoord.Y = Ypos - ScreenBuffer->ShowY;
2022   Reply->Header.MessageSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2023   Reply->Header.DataSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2024
2025   UNLOCK;
2026
2027   return(Reply->Status);
2028 }
2029
2030
2031 CSR_API(CsrGetNumberOfConsoleInputEvents)
2032 {
2033   NTSTATUS Status;
2034   PCSRSS_CONSOLE Console;
2035   PLIST_ENTRY CurrentItem;
2036   DWORD NumEvents;
2037   
2038   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2039   Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2040
2041   LOCK;
2042
2043   Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2044   if (!NT_SUCCESS(Status))
2045     {
2046       Reply->Status = Status;
2047       UNLOCK;
2048       return(Reply->Status);
2049     }
2050
2051   if (Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2052     {
2053       Reply->Status = STATUS_INVALID_HANDLE;
2054       UNLOCK;
2055       return(Reply->Status);
2056     }
2057   
2058   CurrentItem = &Console->InputEvents;
2059   NumEvents = 0;
2060   
2061   // If there are any events ...
2062   if(CurrentItem->Flink != CurrentItem)
2063   {
2064     do
2065     {
2066       CurrentItem = CurrentItem->Flink;
2067       ++NumEvents;
2068     }while(CurrentItem != &Console->InputEvents);
2069   }
2070   
2071   UNLOCK;
2072   
2073   Reply->Status = STATUS_SUCCESS;
2074   Reply->Data.GetNumInputEventsReply.NumInputEvents = NumEvents;
2075    
2076   return Reply->Status;
2077 }
2078
2079
2080 CSR_API(CsrPeekConsoleInput)
2081 {
2082    NTSTATUS Status;
2083    PCSRSS_CONSOLE Console;
2084    DWORD Size;
2085    DWORD Length;
2086    PLIST_ENTRY CurrentItem;
2087    PLIST_ENTRY NextItem;
2088    PINPUT_RECORD InputRecord;
2089    ConsoleInput* Item;
2090    UINT NumItems;
2091    
2092    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2093    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2094    
2095    LOCK;
2096    
2097    Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2098    if(!NT_SUCCESS(Status))
2099    {
2100       Reply->Status = Status;
2101       UNLOCK;
2102       return Reply->Status;
2103    }
2104
2105    if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2106    {
2107       Reply->Status = STATUS_INVALID_HANDLE;
2108       UNLOCK;
2109       return Reply->Status;
2110    }
2111    
2112    InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2113    Length = Request->Data.PeekConsoleInputRequest.Length;
2114    Size = Length * sizeof(INPUT_RECORD);
2115    
2116     if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2117          || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2118    {
2119       UNLOCK;
2120       Reply->Status = STATUS_ACCESS_VIOLATION;
2121       return Reply->Status ;
2122    }
2123    
2124    NumItems = 0;
2125    
2126    if(!IsListEmpty(&Console->InputEvents))
2127    {
2128       CurrentItem = &Console->InputEvents;
2129    
2130       while(NumItems < Length)
2131       {
2132          ++NumItems;
2133          Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2134          *InputRecord++ = Item->InputEvent;
2135          
2136          if(CurrentItem->Flink == &Console->InputEvents)
2137             break;
2138          else
2139             CurrentItem = CurrentItem->Flink;
2140       }
2141    }
2142
2143    UNLOCK;
2144    
2145    Reply->Status = STATUS_SUCCESS;
2146    Reply->Data.PeekConsoleInputReply.Length = NumItems;
2147    return Reply->Status;
2148 }
2149
2150 /* EOF */