update for HEAD-2003021201
[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        {
579          y = 0;
580          SrcOffset = Region.Left * 2;
581        }
582        else
583        {
584          SrcOffset += SrcDelta;
585        }
586      }
587    Mode.dwMode = ENABLE_PROCESSED_OUTPUT;
588    Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
589      IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
590    if( !NT_SUCCESS( Status ) )
591      {
592        DbgPrint( "CSR: Failed to set console mode\n" );
593        return;
594      }
595    Status = CsrpSetConsoleDeviceCursor(
596      ScreenBuffer,
597      ScreenBuffer->CurrentX - ScreenBuffer->ShowX,
598      ((ScreenBuffer->CurrentY + ScreenBuffer->MaxY) - ScreenBuffer->ShowY) % ScreenBuffer->MaxY);
599    if( !NT_SUCCESS( Status ) )
600      {
601        DbgPrint( "CSR: Failed to set console info\n" );
602        return;
603      }
604    Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
605      IOCTL_CONSOLE_SET_CURSOR_INFO, &ScreenBuffer->CursorInfo,
606      sizeof( ScreenBuffer->CursorInfo ), 0, 0 );
607    if( !NT_SUCCESS( Status ) )
608      {
609        DbgPrint( "CSR: Failed to set cursor info\n" );
610        return;
611      }
612 }
613
614
615 CSR_API(CsrWriteConsole)
616 {
617    BYTE *Buffer = Request->Data.WriteConsoleRequest.Buffer;
618    PCSRSS_SCREEN_BUFFER Buff;
619    
620    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
621    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
622      sizeof(LPC_MESSAGE);
623
624    LOCK;
625    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle,
626      (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
627       {
628          UNLOCK;
629          return Reply->Status = STATUS_INVALID_HANDLE;
630       }
631    CsrpWriteConsole( Buff, Buffer, Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE );
632    UNLOCK;
633    return Reply->Status = STATUS_SUCCESS;
634 }
635
636
637 NTSTATUS STDCALL CsrInitConsoleScreenBuffer( PCSRSS_SCREEN_BUFFER Console )
638 {
639   Console->Header.Type = CSRSS_SCREEN_BUFFER_MAGIC;
640   Console->Header.ReferenceCount = 0;
641   Console->MaxX = PhysicalConsoleSize.X;
642   Console->MaxY = PhysicalConsoleSize.Y;
643   Console->ShowX = 0;
644   Console->ShowY = 0;
645   Console->CurrentX = 0;
646   Console->CurrentY = 0;
647   Console->Buffer = RtlAllocateHeap( CsrssApiHeap, 0, Console->MaxX * Console->MaxY * 2 );
648   if( Console->Buffer == 0 )
649     return STATUS_INSUFFICIENT_RESOURCES;
650   Console->DefaultAttrib = 0x17;
651   /* initialize buffer to be empty with default attributes */
652   for( ; Console->CurrentY < Console->MaxY; Console->CurrentY++ )
653     {
654             ClearLineBuffer (Console, 0);
655     }
656   Console->CursorInfo.bVisible = TRUE;
657   Console->CursorInfo.dwSize = 5;
658   Console->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
659   Console->CurrentX = 0;
660   Console->CurrentY = 0;
661   return STATUS_SUCCESS;
662 }
663
664 VOID STDCALL CsrDeleteScreenBuffer( PCSRSS_SCREEN_BUFFER Buffer )
665 {
666   RtlFreeHeap( CsrssApiHeap, 0, Buffer->Buffer );
667   RtlFreeHeap( CsrssApiHeap, 0, Buffer );
668 }
669
670 NTSTATUS STDCALL CsrInitConsole(PCSRSS_CONSOLE Console)
671 {
672   NTSTATUS Status;
673   OBJECT_ATTRIBUTES ObjectAttributes;
674
675   Console->Title.MaximumLength = Console->Title.Length = 0;
676   Console->Title.Buffer = 0;
677   
678   RtlCreateUnicodeString( &Console->Title, L"Command Prompt" );
679   
680   Console->Header.ReferenceCount = 0;
681   Console->WaitingChars = 0;
682   Console->WaitingLines = 0;
683   Console->EchoCount = 0;
684   Console->Header.Type = CSRSS_CONSOLE_MAGIC;
685   Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
686   Console->EarlyReturn = FALSE;
687   InitializeListHead(&Console->InputEvents);
688
689   InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_INHERIT, NULL, NULL);
690
691   Status = NtCreateEvent( &Console->ActiveEvent, STANDARD_RIGHTS_ALL, &ObjectAttributes, FALSE, FALSE );
692   if( !NT_SUCCESS( Status ) )
693     {
694       return Status;
695     }
696   Console->ActiveBuffer = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
697   if( !Console->ActiveBuffer )
698      {
699         NtClose( Console->ActiveEvent );
700         return STATUS_INSUFFICIENT_RESOURCES;
701      }
702   Status = CsrInitConsoleScreenBuffer( Console->ActiveBuffer );
703   if( !NT_SUCCESS( Status ) )
704      {
705         NtClose( Console->ActiveEvent );
706         RtlFreeHeap( CsrssApiHeap, 0, Console->ActiveBuffer );
707         return Status;
708      }
709   /* add a reference count because the buffer is tied to the console */
710   Console->ActiveBuffer->Header.ReferenceCount++;
711   /* make console active, and insert into console list */
712   LOCK;
713   if( ActiveConsole )
714      {
715         Console->Prev = ActiveConsole;
716         Console->Next = ActiveConsole->Next;
717         ActiveConsole->Next->Prev = Console;
718         ActiveConsole->Next = Console;
719      }
720   else {
721      Console->Prev = Console;
722      Console->Next = Console;
723   }
724   ActiveConsole = Console;
725   /* copy buffer contents to screen */
726   CsrDrawConsole( Console->ActiveBuffer );
727   UNLOCK;
728   return STATUS_SUCCESS;
729 }
730
731 /***************************************************************
732  *  CsrDrawConsole blasts the console buffer onto the screen   *
733  *  must be called while holding the active console lock       *
734  **************************************************************/
735 VOID STDCALL CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff )
736 {
737    SMALL_RECT Region;
738
739    CsrpInitRect(
740      Region,
741      Buff->ShowY,
742      Buff->ShowX,
743      Buff->ShowY + PhysicalConsoleSize.Y - 1,
744      Buff->ShowX + PhysicalConsoleSize.X - 1);
745
746    CsrpDrawRegion(Buff, Region);
747 }
748
749
750 VOID STDCALL CsrDeleteConsole( PCSRSS_CONSOLE Console )
751 {
752    ConsoleInput *Event;
753    DPRINT( "CsrDeleteConsole\n" );
754    LOCK;
755    /* Drain input event queue */
756    while( Console->InputEvents.Flink != &Console->InputEvents )
757       {
758          Event = (ConsoleInput *)Console->InputEvents.Flink;
759          Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
760          Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
761          RtlFreeHeap( CsrssApiHeap, 0, Event );
762       }
763    /* Switch to next console */
764    if( ActiveConsole == Console )
765       {
766          if( Console->Next != Console )
767             {
768                ActiveConsole = Console->Next;
769                Console->Prev->Next = Console->Next;
770                Console->Next->Prev = Console->Prev;
771             }
772          else ActiveConsole = 0;
773       }
774    if( ActiveConsole )
775      CsrDrawConsole( ActiveConsole->ActiveBuffer );
776    UNLOCK;
777    if( !--Console->ActiveBuffer->Header.ReferenceCount )
778      CsrDeleteScreenBuffer( Console->ActiveBuffer );
779    NtClose( Console->ActiveEvent );
780    RtlFreeUnicodeString( &Console->Title );
781    RtlFreeHeap( CsrssApiHeap, 0, Console );
782 }
783
784 VOID STDCALL CsrInitConsoleSupport(VOID)
785 {
786    OBJECT_ATTRIBUTES ObjectAttributes;
787    UNICODE_STRING DeviceName;
788    NTSTATUS Status;
789    IO_STATUS_BLOCK Iosb;
790    CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
791    
792    DPRINT("CSR: CsrInitConsoleSupport()\n");
793    
794    RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\BlueScreen");
795    InitializeObjectAttributes(&ObjectAttributes,
796                               &DeviceName,
797                               0,
798                               NULL,
799                               NULL);
800    Status = NtOpenFile(&ConsoleDeviceHandle,
801                        FILE_ALL_ACCESS,
802                        &ObjectAttributes,
803                        &Iosb,
804                        0,
805                        FILE_SYNCHRONOUS_IO_ALERT);
806    if (!NT_SUCCESS(Status))
807      {
808         DbgPrint("CSR: Failed to open console. Expect problems.\n");
809      }
810
811    RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\Keyboard");
812    InitializeObjectAttributes(&ObjectAttributes,
813                               &DeviceName,
814                               0,
815                               NULL,
816                               NULL);
817    Status = NtOpenFile(&KeyboardDeviceHandle,
818                        FILE_ALL_ACCESS,
819                        &ObjectAttributes,
820                        &Iosb,
821                        0,
822                        0);
823    if (!NT_SUCCESS(Status))
824      {
825         DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
826      }
827    
828    ActiveConsole = 0;
829    RtlInitializeCriticalSection( &ActiveConsoleLock );
830    Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, &ScrInfo, sizeof( ScrInfo ) );
831    if( !NT_SUCCESS( Status ) )
832      {
833        DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
834        return;
835      }
836    PhysicalConsoleSize = ScrInfo.dwSize;
837 }
838
839 VOID Console_Api( DWORD RefreshEvent )
840 {
841   /* keep reading events from the keyboard and stuffing them into the current
842      console's input queue */
843   ConsoleInput *KeyEventRecord;
844   ConsoleInput *TempInput;
845   IO_STATUS_BLOCK Iosb;
846   NTSTATUS Status;
847   HANDLE Events[2];     // 0 = keyboard, 1 = refresh
848   int c;
849   int updown;
850   PCSRSS_CONSOLE SwapConsole = 0; // console we are thinking about swapping with
851
852   Events[0] = 0;
853   Status = NtCreateEvent( &Events[0], STANDARD_RIGHTS_ALL, NULL, FALSE, FALSE );
854   if( !NT_SUCCESS( Status ) )
855     {
856       DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status );
857       NtTerminateProcess( NtCurrentProcess(), Status );
858     }
859   Events[1] = (HANDLE)RefreshEvent;
860   while( 1 )
861     {
862       KeyEventRecord = RtlAllocateHeap(CsrssApiHeap, 
863                                        0,
864                                        sizeof(ConsoleInput));
865        if ( KeyEventRecord == 0 )
866         {
867           DbgPrint( "CSR: Memory allocation failure!" );
868           continue;
869         }
870       KeyEventRecord->InputEvent.EventType = KEY_EVENT;
871       Status = NtReadFile( KeyboardDeviceHandle, Events[0], NULL, NULL, &Iosb,
872         &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 );
873       if( !NT_SUCCESS( Status ) )
874         {
875           DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
876           RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
877           continue;
878         }
879       if( Status == STATUS_PENDING )
880         {
881           while( 1 )
882             {
883               Status = NtWaitForMultipleObjects( 2, Events, WaitAny, FALSE, NULL );
884               if( Status == STATUS_WAIT_0 + 1 )
885                 {
886                   LOCK;
887                   CsrDrawConsole( ActiveConsole->ActiveBuffer );
888                   UNLOCK;
889                   continue;
890                 }
891               else if( Status != STATUS_WAIT_0 )
892                 {
893                   DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status );
894                   NtTerminateProcess( NtCurrentProcess(), Status );
895                 }
896               else break;
897             }
898         }
899       if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
900         ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED )&&
901           KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_TAB )
902          if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
903             {
904               ANSI_STRING Title;
905               void * Buffer;
906               COORD *pos;
907               unsigned int src, dst;
908               
909                /* alt-tab, swap consoles */
910                // move SwapConsole to next console, and print its title
911               LOCK;
912               if( !SwapConsole )
913                 SwapConsole = ActiveConsole;
914               
915               if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED )
916                 SwapConsole = SwapConsole->Prev;
917               else SwapConsole = SwapConsole->Next;
918               Title.MaximumLength = RtlUnicodeStringToAnsiSize( &SwapConsole->Title );
919               Title.Length = 0;
920               Buffer = RtlAllocateHeap( CsrssApiHeap,
921                                         0,
922                                         sizeof( COORD ) + Title.MaximumLength );
923               pos = (COORD *)Buffer;
924               Title.Buffer = Buffer + sizeof( COORD );
925
926               /* this does not seem to work
927                  RtlUnicodeStringToAnsiString( &Title, &SwapConsole->Title, FALSE ); */
928               // temp hack
929               for( src = 0, dst = 0; src < SwapConsole->Title.Length; src++, dst++ )
930                 Title.Buffer[dst] = (char)SwapConsole->Title.Buffer[dst];
931               
932               pos->Y = PhysicalConsoleSize.Y / 2;
933               pos->X = ( PhysicalConsoleSize.X - Title.MaximumLength ) / 2;
934               // redraw the console to clear off old title
935               CsrDrawConsole( ActiveConsole->ActiveBuffer );
936               Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
937                                               NULL,
938                                               NULL,
939                                               NULL,
940                                               &Iosb,
941                                               IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
942                                               0,
943                                               0,
944                                               Buffer,
945                                               sizeof (COORD) + Title.MaximumLength );
946               if( !NT_SUCCESS( Status ) )
947                 {
948                   DPRINT1( "Error writing to console\n" );
949                 }
950               RtlFreeHeap( CsrssApiHeap, 0, Buffer );
951               
952               UNLOCK;
953               RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
954               continue;
955             }
956          else {
957             RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
958             continue;
959          }
960       else if( SwapConsole &&
961                KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_MENU &&
962                KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == FALSE )
963         {
964           // alt key released, swap consoles
965           PCSRSS_CONSOLE tmp;
966
967           LOCK;
968           if( SwapConsole != ActiveConsole )
969             {
970               // first remove swapconsole from the list
971               SwapConsole->Prev->Next = SwapConsole->Next;
972               SwapConsole->Next->Prev = SwapConsole->Prev;
973               // now insert before activeconsole
974               SwapConsole->Next = ActiveConsole;
975               SwapConsole->Prev = ActiveConsole->Prev;
976               ActiveConsole->Prev->Next = SwapConsole;
977               ActiveConsole->Prev = SwapConsole;
978             }
979           ActiveConsole = SwapConsole;
980           SwapConsole = 0;
981           CsrDrawConsole( ActiveConsole->ActiveBuffer );
982
983           UNLOCK;
984         }
985       if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
986         ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) &&
987         ( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP ||
988           KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) )
989          {
990             if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
991                {
992                   /* scroll up or down */
993                   LOCK;
994                   if( ActiveConsole == 0 )
995                      {
996                         DbgPrint( "CSR: No Active Console!\n" );
997                         UNLOCK;
998                         RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
999                         continue;
1000                      }
1001                   if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP )
1002                      {
1003                         /* only scroll up if there is room to scroll up into */
1004                         if( ActiveConsole->ActiveBuffer->ShowY != ((ActiveConsole->ActiveBuffer->CurrentY + 1) %
1005         ActiveConsole->ActiveBuffer->MaxY) )
1006                            ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY +
1007          ActiveConsole->ActiveBuffer->MaxY - 1) % ActiveConsole->ActiveBuffer->MaxY;
1008                      }
1009                   else if( ActiveConsole->ActiveBuffer->ShowY != ActiveConsole->ActiveBuffer->CurrentY )
1010                      /* only scroll down if there is room to scroll down into */
1011                      if( ActiveConsole->ActiveBuffer->ShowY % ActiveConsole->ActiveBuffer->MaxY != 
1012            ActiveConsole->ActiveBuffer->CurrentY )
1013
1014                         if( ((ActiveConsole->ActiveBuffer->CurrentY + 1) % ActiveConsole->ActiveBuffer->MaxY) != 
1015         (ActiveConsole->ActiveBuffer->ShowY + PhysicalConsoleSize.Y) % ActiveConsole->ActiveBuffer->MaxY )
1016                            ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY + 1) %
1017          ActiveConsole->ActiveBuffer->MaxY;
1018                   CsrDrawConsole( ActiveConsole->ActiveBuffer );
1019                   UNLOCK;
1020                }
1021             RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1022             continue;
1023         }
1024       LOCK;
1025       if( ActiveConsole == 0 )
1026          {
1027             DbgPrint( "CSR: No Active Console!\n" );
1028             UNLOCK;
1029             RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1030             continue;
1031          }
1032       // process special keys if enabled
1033       if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) )
1034           switch( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar )
1035             {
1036             case '\r':
1037               // add a \n to the queue as well
1038               // first add the \r
1039               updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
1040               KeyEventRecord->Echoed = FALSE;
1041               KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
1042         InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1043               ActiveConsole->WaitingChars++;
1044               KeyEventRecord = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( ConsoleInput ) );
1045               if( !KeyEventRecord )
1046                 {
1047                   DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
1048                   UNLOCK;
1049                   continue;
1050                 }
1051               KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1052               KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
1053               KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
1054               KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
1055               KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
1056             }
1057       // add event to the queue
1058       InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1059       // if line input mode is enabled, only wake the client on enter key down
1060       if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT ) ||
1061           ActiveConsole->EarlyReturn ||
1062           ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' &&
1063             KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) )
1064         {
1065           NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1066           if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1067              ActiveConsole->WaitingLines++;
1068         }
1069       KeyEventRecord->Echoed = FALSE;
1070       if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) &&
1071           KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' &&
1072           KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown )
1073          {
1074             // walk the input queue looking for a char to backspace
1075             for( TempInput = (ConsoleInput *)ActiveConsole->InputEvents.Blink;
1076                   TempInput != (ConsoleInput *)&ActiveConsole->InputEvents &&
1077                   (TempInput->InputEvent.EventType != KEY_EVENT ||
1078                   TempInput->InputEvent.Event.KeyEvent.bKeyDown == FALSE ||
1079                   TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' );
1080                   TempInput = (ConsoleInput *)TempInput->ListEntry.Blink );
1081             // if we found one, delete it, otherwise, wake the client
1082             if( TempInput != (ConsoleInput *)&ActiveConsole->InputEvents )
1083                {
1084                   // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
1085       RemoveEntryList(&TempInput->ListEntry);
1086                   if( TempInput->Echoed )
1087                      CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1088                   RtlFreeHeap( CsrssApiHeap, 0, TempInput );
1089       RemoveEntryList(&KeyEventRecord->ListEntry);
1090                   RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1091                   ActiveConsole->WaitingChars -= 2;
1092                }
1093             else NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1094    }
1095       else {
1096          // echo chars if we are supposed to and client is waiting for some
1097          if( ( ActiveConsole->Mode & ENABLE_ECHO_INPUT ) && ActiveConsole->EchoCount &&
1098              KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar &&
1099              KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE &&
1100              KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
1101             {
1102                // mark the char as already echoed
1103                CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1104                ActiveConsole->EchoCount--;
1105                KeyEventRecord->Echoed = TRUE;
1106             }
1107       }
1108       ActiveConsole->WaitingChars++;
1109       if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT) )
1110         NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1111       UNLOCK;
1112     }
1113 }
1114
1115 CSR_API(CsrGetScreenBufferInfo)
1116 {
1117    NTSTATUS Status;
1118    PCSRSS_SCREEN_BUFFER Buff;
1119    PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1120    IO_STATUS_BLOCK Iosb;
1121    
1122    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1123    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1124      sizeof(LPC_MESSAGE);
1125
1126    LOCK;
1127    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle,
1128      (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1129       {
1130          UNLOCK;
1131          return Reply->Status = STATUS_INVALID_HANDLE;
1132       }
1133    pInfo = &Reply->Data.ScreenBufferInfoReply.Info;
1134    if( Buff == ActiveConsole->ActiveBuffer )
1135      {
1136         Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1137     IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, pInfo, sizeof( *pInfo ) );
1138         if( !NT_SUCCESS( Status ) )
1139            DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
1140         Reply->Status = Status;
1141      }
1142    else {
1143       pInfo->dwSize.X = PhysicalConsoleSize.X;
1144       pInfo->dwSize.Y = PhysicalConsoleSize.Y;
1145       pInfo->dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1146       pInfo->dwCursorPosition.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1147       pInfo->wAttributes = Buff->DefaultAttrib;
1148       pInfo->srWindow.Left = 0;
1149       pInfo->srWindow.Right = PhysicalConsoleSize.X - 1;
1150       pInfo->srWindow.Top = 0;
1151       pInfo->srWindow.Bottom = PhysicalConsoleSize.Y - 1;
1152       Reply->Status = STATUS_SUCCESS;
1153    }
1154    UNLOCK;
1155    return Reply->Status;
1156 }
1157
1158 CSR_API(CsrSetCursor)
1159 {
1160    NTSTATUS Status;
1161    PCSRSS_SCREEN_BUFFER Buff;
1162    CONSOLE_SCREEN_BUFFER_INFO Info;
1163    IO_STATUS_BLOCK Iosb;
1164    
1165    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1166    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1167      sizeof(LPC_MESSAGE);
1168
1169    LOCK;
1170    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.SetCursorRequest.ConsoleHandle,
1171      (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1172       {
1173          UNLOCK;
1174          return Reply->Status = STATUS_INVALID_HANDLE;
1175       }
1176    Info.dwCursorPosition = Request->Data.SetCursorRequest.Position;
1177    Info.wAttributes = Buff->DefaultAttrib;
1178    if( Buff == ActiveConsole->ActiveBuffer )
1179       {
1180          Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1181      IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &Info, sizeof( Info ), 0, 0 );
1182         if( !NT_SUCCESS( Status ) )
1183            DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
1184       }
1185
1186    Buff->CurrentX = Info.dwCursorPosition.X + Buff->ShowX;
1187    Buff->CurrentY = (Info.dwCursorPosition.Y + Buff->ShowY) % Buff->MaxY;
1188    UNLOCK;
1189    return Reply->Status = Status;
1190 }
1191
1192 CSR_API(CsrWriteConsoleOutputChar)
1193 {
1194    BYTE *Buffer = Request->Data.WriteConsoleOutputCharRequest.String;
1195    PCSRSS_SCREEN_BUFFER Buff;
1196    DWORD X, Y;
1197    NTSTATUS Status;
1198    IO_STATUS_BLOCK Iosb;
1199    
1200    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1201    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1202      sizeof(LPC_MESSAGE);
1203    LOCK;
1204    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1205       {
1206          UNLOCK;
1207          return Reply->Status = STATUS_INVALID_HANDLE;
1208       }
1209    X = Buff->CurrentX;
1210    Y = Buff->CurrentY;
1211    Buff->CurrentX = Request->Data.WriteConsoleOutputCharRequest.Coord.X;
1212    Buff->CurrentY = Request->Data.WriteConsoleOutputCharRequest.Coord.Y;
1213    Buffer[Request->Data.WriteConsoleOutputCharRequest.Length] = 0;
1214    CsrpWriteConsole( Buff, Buffer, Request->Data.WriteConsoleOutputCharRequest.Length, FALSE );
1215    if( ActiveConsole->ActiveBuffer == Buff )
1216      {
1217        Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1218                                        NULL,
1219                                        NULL,
1220                                        NULL,
1221                                        &Iosb,
1222                                        IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
1223                                        0,
1224                                        0,
1225                                        &Request->Data.WriteConsoleOutputCharRequest.Coord,
1226                                        sizeof (COORD) + Request->Data.WriteConsoleOutputCharRequest.Length );
1227        if( !NT_SUCCESS( Status ) )
1228          DPRINT1( "Failed to write output chars: %x\n", Status );
1229      }
1230    Reply->Data.WriteConsoleOutputCharReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1231    Reply->Data.WriteConsoleOutputCharReply.EndCoord.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1232    Buff->CurrentY = Y;
1233    Buff->CurrentX = X;
1234    UNLOCK;
1235    return Reply->Status = STATUS_SUCCESS;
1236 }
1237
1238 CSR_API(CsrFillOutputChar)
1239 {
1240    PCSRSS_SCREEN_BUFFER Buff;
1241    DWORD X, Y, i;
1242    
1243    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1244    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1245      sizeof(LPC_MESSAGE);
1246
1247    LOCK;
1248    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1249       {
1250          UNLOCK;
1251          return Reply->Status = STATUS_INVALID_HANDLE;
1252       }
1253    X = Request->Data.FillOutputRequest.Position.X + Buff->ShowX;
1254    Y = Request->Data.FillOutputRequest.Position.Y + Buff->ShowY;
1255    for( i = 0; i < Request->Data.FillOutputRequest.Length; i++ )
1256       {
1257          Buff->Buffer[ (Y * 2 * Buff->MaxX) + (X * 2) ] = Request->Data.FillOutputRequest.Char;
1258          if( ++X == Buff->MaxX )
1259             {
1260                if( ++Y == Buff->MaxY )
1261                   Y = 0;
1262                X = 0;
1263             }
1264       }
1265    if( Buff == ActiveConsole->ActiveBuffer )
1266       CsrDrawConsole( Buff );
1267    UNLOCK;
1268    return Reply->Status;
1269 }
1270
1271 CSR_API(CsrReadInputEvent)
1272 {
1273    PLIST_ENTRY CurrentEntry;
1274    PCSRSS_CONSOLE Console;
1275    NTSTATUS Status;
1276    ConsoleInput *Input;
1277    
1278    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1279    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1280       sizeof(LPC_MESSAGE);
1281    Reply->Data.ReadInputReply.Event = ProcessData->ConsoleEvent;
1282    
1283    LOCK;
1284    Status = CsrGetObject( ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, (Object_t **)&Console );
1285    if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? 0 : STATUS_INVALID_HANDLE))
1286       {
1287          Reply->Status = Status;
1288          UNLOCK;
1289          return Status;
1290       }
1291
1292    // only get input if there is any
1293    if( Console->InputEvents.Flink != &Console->InputEvents )
1294      {
1295        CurrentEntry = RemoveHeadList(&Console->InputEvents);
1296        Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1297        Reply->Data.ReadInputReply.Input = Input->InputEvent;
1298
1299        if( Input->InputEvent.EventType == KEY_EVENT )
1300          {
1301            if( Console->Mode & ENABLE_LINE_INPUT &&
1302                Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE &&
1303                Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1304              Console->WaitingLines--;
1305            Console->WaitingChars--;
1306          }
1307        RtlFreeHeap( CsrssApiHeap, 0, Input );
1308        Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents) ? TRUE : FALSE;
1309        Status = STATUS_SUCCESS;
1310        Console->EarlyReturn = FALSE; // clear early return
1311      }
1312    else {
1313       Status = STATUS_PENDING;
1314       Console->EarlyReturn = TRUE;  // mark for early return
1315    }
1316    UNLOCK;
1317    return Reply->Status = Status;
1318 }
1319
1320 CSR_API(CsrWriteConsoleOutputAttrib)
1321 {
1322    int c;
1323    PCSRSS_SCREEN_BUFFER Buff;
1324    NTSTATUS Status;
1325    int X, Y;
1326    IO_STATUS_BLOCK Iosb;
1327    
1328    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1329    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1330       sizeof(LPC_MESSAGE);
1331    LOCK;
1332    Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1333    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1334       {
1335          Reply->Status = Status;
1336          UNLOCK;
1337          return Status;
1338       }
1339    X = Buff->CurrentX;
1340    Y = Buff->CurrentY;
1341    Buff->CurrentX = Request->Data.WriteConsoleOutputAttribRequest.Coord.X + Buff->ShowX;
1342    Buff->CurrentY = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1343    for( c = 0; c < Request->Data.WriteConsoleOutputAttribRequest.Length; c++ )
1344       {
1345          Buff->Buffer[(Buff->CurrentY * Buff->MaxX * 2) + (Buff->CurrentX * 2) + 1] = Request->Data.WriteConsoleOutputAttribRequest.String[c];
1346          if( ++Buff->CurrentX == Buff->MaxX )
1347             {
1348                Buff->CurrentX = 0;
1349                if( ++Buff->CurrentY == Buff->MaxY )
1350                   Buff->CurrentY = 0;
1351             }
1352       }
1353    if( Buff == ActiveConsole->ActiveBuffer )
1354       {
1355         Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1356                                         NULL,
1357                                         NULL,
1358                                         NULL,
1359                                         &Iosb,
1360                                         IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE,
1361                                         0,
1362                                         0,
1363                                         &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1364                                         Request->Data.WriteConsoleOutputAttribRequest.Length +
1365                                         sizeof (COORD) );
1366         if( !NT_SUCCESS( Status ) )
1367           DPRINT1( "Failed to write output attributes to console\n" );
1368       }
1369    Reply->Data.WriteConsoleOutputAttribReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1370    Reply->Data.WriteConsoleOutputAttribReply.EndCoord.Y = ( Buff->CurrentY + Buff->MaxY - Buff->ShowY ) % Buff->MaxY;
1371    Buff->CurrentX = X;
1372    Buff->CurrentY = Y;
1373    UNLOCK;
1374    return Reply->Status = STATUS_SUCCESS;
1375 }
1376
1377 CSR_API(CsrFillOutputAttrib)
1378 {
1379    int c;
1380    PCSRSS_SCREEN_BUFFER Buff;
1381    NTSTATUS Status;
1382    int X, Y;
1383    IO_STATUS_BLOCK Iosb;
1384    OUTPUT_ATTRIBUTE Attr;
1385    
1386    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1387    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1388       sizeof(LPC_MESSAGE);
1389    LOCK;
1390    Status = CsrGetObject( ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1391    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1392       {
1393          Reply->Status = Status;
1394          UNLOCK;
1395          return Status;
1396       }
1397    X = Buff->CurrentX;
1398    Y = Buff->CurrentY;
1399    Buff->CurrentX = Request->Data.FillOutputAttribRequest.Coord.X + Buff->ShowX;
1400    Buff->CurrentY = Request->Data.FillOutputAttribRequest.Coord.Y + Buff->ShowY;
1401    for( c = 0; c < Request->Data.FillOutputAttribRequest.Length; c++ )
1402       {
1403          Buff->Buffer[(Buff->CurrentY * Buff->MaxX * 2) + (Buff->CurrentX * 2) + 1] = Request->Data.FillOutputAttribRequest.Attribute;
1404          if( ++Buff->CurrentX == Buff->MaxX )
1405             {
1406                Buff->CurrentX = 0;
1407                if( ++Buff->CurrentY == Buff->MaxY )
1408                   Buff->CurrentY = 0;
1409             }
1410       }
1411    if( Buff == ActiveConsole->ActiveBuffer )
1412      {
1413        Attr.wAttribute = Request->Data.FillOutputAttribRequest.Attribute;
1414        Attr.nLength = Request->Data.FillOutputAttribRequest.Length;
1415        Attr.dwCoord = Request->Data.FillOutputAttribRequest.Coord;
1416        Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1417                                        NULL,
1418                                        NULL,
1419                                        NULL,
1420                                        &Iosb,
1421                                        IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE,
1422                                        &Attr,
1423                                        sizeof (Attr),
1424                                        0,
1425                                        0 );
1426        if( !NT_SUCCESS( Status ) )
1427          DPRINT1( "Failed to fill output attribute\n" );
1428      }
1429    Buff->CurrentX = X;
1430    Buff->CurrentY = Y;
1431    UNLOCK;
1432    return Reply->Status = STATUS_SUCCESS;
1433 }
1434
1435
1436 CSR_API(CsrGetCursorInfo)
1437 {
1438    PCSRSS_SCREEN_BUFFER Buff;
1439    NTSTATUS Status;
1440    
1441    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1442    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1443       sizeof(LPC_MESSAGE);
1444    LOCK;
1445    Status = CsrGetObject( ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1446    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1447       {
1448          Reply->Status = Status;
1449          UNLOCK;
1450          return Status;
1451       }
1452    Reply->Data.GetCursorInfoReply.Info = Buff->CursorInfo;
1453    UNLOCK;
1454    return Reply->Status = STATUS_SUCCESS;
1455 }
1456
1457 CSR_API(CsrSetCursorInfo)
1458 {
1459    PCSRSS_SCREEN_BUFFER Buff;
1460    NTSTATUS Status;
1461    IO_STATUS_BLOCK Iosb;
1462    
1463    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1464    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1465       sizeof(LPC_MESSAGE);
1466    LOCK;
1467    Status = CsrGetObject( ProcessData,
1468      Request->Data.SetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1469
1470    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1471       {
1472          Reply->Status = Status;
1473          UNLOCK;
1474          return Status;
1475       }
1476    Buff->CursorInfo = Request->Data.SetCursorInfoRequest.Info;
1477    if( Buff == ActiveConsole->ActiveBuffer )
1478       {
1479          Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_CURSOR_INFO, &Buff->CursorInfo, sizeof( Buff->CursorInfo ), 0, 0 );
1480          if( !NT_SUCCESS( Status ) )
1481             {
1482                DbgPrint( "CSR: Failed to set cursor info\n" );
1483                return Reply->Status = Status;
1484             }
1485       }
1486    UNLOCK;
1487    return Reply->Status = STATUS_SUCCESS;
1488 }
1489
1490 CSR_API(CsrSetTextAttrib)
1491 {
1492    NTSTATUS Status;
1493    CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
1494    IO_STATUS_BLOCK Iosb;
1495    PCSRSS_SCREEN_BUFFER Buff;
1496    
1497    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1498    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1499       sizeof(LPC_MESSAGE);
1500    LOCK;
1501    Status = CsrGetObject( ProcessData, Request->Data.SetAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1502    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1503       {
1504          Reply->Status = Status;
1505          UNLOCK;
1506          return Status;
1507       }
1508    Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1509    if( Buff == ActiveConsole->ActiveBuffer )
1510       {
1511          ScrInfo.wAttributes = Buff->DefaultAttrib;
1512          ScrInfo.dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;   
1513          ScrInfo.dwCursorPosition.Y = ((Buff->CurrentY + Buff->MaxY) - Buff->ShowY) % Buff->MaxY;
1514          Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
1515          if( !NT_SUCCESS( Status ) )
1516             {
1517                DbgPrint( "CSR: Failed to set console info\n" );
1518                UNLOCK;
1519                return Reply->Status = Status;
1520             }
1521       }
1522    UNLOCK;
1523    return Reply->Status = STATUS_SUCCESS;
1524 }
1525
1526 CSR_API(CsrSetConsoleMode)
1527 {
1528    NTSTATUS Status;
1529    PCSRSS_CONSOLE Console;
1530    PCSRSS_SCREEN_BUFFER Buff;
1531
1532    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1533    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1534    LOCK;
1535    Status = CsrGetObject( ProcessData,
1536      Request->Data.SetConsoleModeRequest.ConsoleHandle,
1537      (Object_t **)&Console );
1538    if( !NT_SUCCESS( Status ) )
1539       {
1540          Reply->Status = Status;
1541          UNLOCK;
1542          return Status;
1543       }
1544
1545    Buff = (PCSRSS_SCREEN_BUFFER)Console;
1546    if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1547       Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1548    else if( Console->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1549       Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1550    else {
1551       Reply->Status = STATUS_INVALID_HANDLE;
1552       UNLOCK;
1553       return Status;
1554    }
1555    UNLOCK;
1556    Reply->Status = STATUS_SUCCESS;
1557    return Reply->Status;
1558 }
1559
1560 CSR_API(CsrGetConsoleMode)
1561 {
1562    NTSTATUS Status;
1563    PCSRSS_CONSOLE Console;
1564    PCSRSS_SCREEN_BUFFER Buff;   /* gee, I really wish I could use an anonymous union here */
1565
1566    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1567    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1568    LOCK;
1569    Status = CsrGetObject( ProcessData,
1570      Request->Data.GetConsoleModeRequest.ConsoleHandle,
1571      (Object_t **)&Console );
1572    if( !NT_SUCCESS( Status ) )
1573       {
1574          Reply->Status = Status;
1575          UNLOCK;
1576          return Status;
1577       }
1578    Reply->Status = STATUS_SUCCESS;
1579    Buff = (PCSRSS_SCREEN_BUFFER)Console;
1580    if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1581       Reply->Data.GetConsoleModeReply.ConsoleMode = Console->Mode;
1582    else if( Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1583       Reply->Data.GetConsoleModeReply.ConsoleMode = Buff->Mode;
1584    else Status = STATUS_INVALID_HANDLE;
1585    UNLOCK;
1586    return Reply->Status;
1587 }
1588
1589 CSR_API(CsrCreateScreenBuffer)
1590 {
1591    PCSRSS_SCREEN_BUFFER Buff = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
1592    NTSTATUS Status;
1593    
1594    Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1595    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1596    if( !Buff )
1597       Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
1598    LOCK;
1599    Status = CsrInitConsoleScreenBuffer( Buff );
1600    if( !NT_SUCCESS( Status ) )
1601       Reply->Status = Status;
1602    else {
1603       Status = CsrInsertObject( ProcessData, &Reply->Data.CreateScreenBufferReply.OutputHandle, &Buff->Header );
1604       if( !NT_SUCCESS( Status ) )
1605          Reply->Status = Status;
1606       else Reply->Status = STATUS_SUCCESS;
1607    }
1608    UNLOCK;
1609    return Reply->Status;
1610 }
1611
1612 CSR_API(CsrSetScreenBuffer)
1613 {
1614    NTSTATUS Status;
1615    PCSRSS_SCREEN_BUFFER Buff;
1616    
1617    Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1618    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1619    LOCK;
1620    Status = CsrGetObject( ProcessData, Request->Data.SetActiveScreenBufferRequest.OutputHandle, (Object_t **)&Buff );
1621    if( !NT_SUCCESS( Status ) )
1622       Reply->Status = Status;
1623    else {
1624       // drop reference to old buffer, maybe delete
1625       if( !InterlockedDecrement( &ProcessData->Console->ActiveBuffer->Header.ReferenceCount ) )
1626          CsrDeleteScreenBuffer( ProcessData->Console->ActiveBuffer );
1627       // tie console to new buffer
1628       ProcessData->Console->ActiveBuffer = Buff;
1629       // inc ref count on new buffer
1630       InterlockedIncrement( &Buff->Header.ReferenceCount );
1631       // if the console is active, redraw it
1632       if( ActiveConsole == ProcessData->Console )
1633          CsrDrawConsole( Buff );
1634       Reply->Status = STATUS_SUCCESS;
1635    }
1636    UNLOCK;
1637    return Reply->Status;
1638 }
1639
1640 CSR_API(CsrSetTitle)
1641 {
1642   NTSTATUS Status;
1643   PCSRSS_CONSOLE Console;
1644   
1645   Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1646   Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1647   LOCK;
1648   Status = CsrGetObject( ProcessData, Request->Data.SetTitleRequest.Console, (Object_t **)&Console );
1649   if( !NT_SUCCESS( Status ) )
1650     Reply->Status = Status;  
1651   else {
1652     // copy title to console
1653     RtlFreeUnicodeString( &Console->Title );
1654     RtlCreateUnicodeString( &Console->Title, Request->Data.SetTitleRequest.Title );
1655     Reply->Status = STATUS_SUCCESS;
1656   }
1657   UNLOCK;
1658   return Reply->Status;
1659 }
1660
1661 CSR_API(CsrGetTitle)
1662 {
1663         NTSTATUS        Status;
1664         PCSRSS_CONSOLE  Console;
1665   
1666         Reply->Header.MessageSize = sizeof (CSRSS_API_REPLY);
1667         Reply->Header.DataSize =
1668                 sizeof (CSRSS_API_REPLY)
1669                 - sizeof(LPC_MESSAGE);
1670         LOCK;
1671         Status = CsrGetObject (
1672                         ProcessData,
1673                         Request->Data.GetTitleRequest.ConsoleHandle,
1674                         (Object_t **) & Console
1675                         );
1676         if ( !NT_SUCCESS( Status ) )
1677         {
1678                 Reply->Status = Status;
1679         }
1680         else
1681         {
1682                 HANDLE ConsoleHandle = Request->Data.GetTitleRequest.ConsoleHandle;
1683                 
1684                 /* Copy title of the console to the user title buffer */
1685                 RtlZeroMemory (
1686                         & Reply->Data.GetTitleReply,
1687                         sizeof (CSRSS_GET_TITLE_REPLY)
1688                         );
1689                 Reply->Data.GetTitleReply.ConsoleHandle = ConsoleHandle;
1690                 Reply->Data.GetTitleReply.Length = Console->Title.Length;
1691                 wcscpy (Reply->Data.GetTitleReply.Title, Console->Title.Buffer);
1692                 Reply->Status = STATUS_SUCCESS;
1693         }
1694         UNLOCK;
1695         return Reply->Status;
1696 }
1697
1698 CSR_API(CsrWriteConsoleOutput)
1699 {
1700    SHORT i, X, Y, SizeX, SizeY;
1701    PCSRSS_SCREEN_BUFFER Buff;
1702    SMALL_RECT ScreenBuffer;
1703    CHAR_INFO* CurCharInfo;
1704    SMALL_RECT WriteRegion;
1705    CHAR_INFO* CharInfo;
1706    COORD BufferCoord;
1707    COORD BufferSize;
1708    NTSTATUS Status;
1709    DWORD Offset;
1710    DWORD PSize;
1711
1712    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1713    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1714    LOCK;
1715    Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputRequest.ConsoleHandle, (Object_t **)&Buff );
1716    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1717       {
1718          Reply->Status = Status;
1719          UNLOCK;
1720          return Status;
1721       }
1722
1723    BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
1724    PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
1725    BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
1726    CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
1727    if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
1728        (((PVOID)CharInfo + PSize) > 
1729         (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
1730      {
1731        UNLOCK;
1732        Reply->Status = STATUS_ACCESS_VIOLATION;
1733        return(Reply->Status);
1734      }
1735    WriteRegion = Request->Data.WriteConsoleOutputRequest.WriteRegion;
1736
1737    SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(WriteRegion));
1738    SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(WriteRegion));
1739    WriteRegion.Bottom = WriteRegion.Top + SizeY;
1740    WriteRegion.Right = WriteRegion.Left + SizeX;
1741
1742    /* Make sure WriteRegion is inside the screen buffer */
1743    CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1744    if (!CsrpGetIntersection(&WriteRegion, ScreenBuffer, WriteRegion))
1745       {
1746          UNLOCK;
1747          /* It is okay to have a WriteRegion completely outside the screen buffer.
1748             No data is written then. */
1749          return (Reply->Status = STATUS_SUCCESS);
1750       }
1751
1752    for ( i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++ )
1753    {
1754      CurCharInfo = CharInfo + (i * BufferSize.Y);
1755      Offset = (Y * Buff->MaxX + WriteRegion.Left) * 2;
1756      for ( X = WriteRegion.Left; X <= WriteRegion.Right; X++ )
1757       {
1758         SET_CELL_BUFFER(Buff, Offset, CurCharInfo->Char.AsciiChar, CurCharInfo->Attributes);
1759         CurCharInfo++;
1760       }
1761    }
1762
1763    if( Buff == ActiveConsole->ActiveBuffer )
1764      {
1765         CsrpDrawRegion( ActiveConsole->ActiveBuffer, WriteRegion );
1766      }
1767
1768    UNLOCK;
1769    Reply->Data.WriteConsoleOutputReply.WriteRegion.Right = WriteRegion.Left + SizeX - 1;
1770    Reply->Data.WriteConsoleOutputReply.WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
1771    Reply->Data.WriteConsoleOutputReply.WriteRegion.Left = WriteRegion.Left;
1772    Reply->Data.WriteConsoleOutputReply.WriteRegion.Top = WriteRegion.Top;
1773    return (Reply->Status = STATUS_SUCCESS);
1774 }
1775
1776 CSR_API(CsrFlushInputBuffer)
1777 {
1778   PLIST_ENTRY CurrentEntry;
1779   PLIST_ENTRY NextEntry;
1780   PCSRSS_CONSOLE Console;
1781   ConsoleInput* Input;
1782   NTSTATUS Status;
1783
1784   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1785   Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1786   LOCK;
1787   Status = CsrGetObject( ProcessData, Request->Data.FlushInputBufferRequest.ConsoleInput, (Object_t **)&Console );
1788   if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1789     {
1790         Reply->Status = Status;
1791         UNLOCK;
1792         return Status;
1793     }
1794
1795   /* Discard all entries in the input event queue */
1796   CurrentEntry = Console->InputEvents.Flink;
1797   while (IsListEmpty(&Console->InputEvents))
1798     {
1799   NextEntry = CurrentEntry->Flink;
1800   Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1801   /* Destroy the event */
1802   Console->WaitingChars--;
1803         RtlFreeHeap( CsrssApiHeap, 0, Input );
1804   CurrentEntry = NextEntry;
1805     }
1806   UNLOCK;
1807
1808   return (Reply->Status = STATUS_SUCCESS);
1809 }
1810
1811 CSR_API(CsrScrollConsoleScreenBuffer)
1812 {
1813   SHORT i, X, Y, SizeX, SizeY;
1814   PCSRSS_SCREEN_BUFFER Buff;
1815   SMALL_RECT ScreenBuffer;
1816   SMALL_RECT SrcRegion;
1817   SMALL_RECT DstRegion;
1818   SMALL_RECT FillRegion;
1819   IO_STATUS_BLOCK Iosb;
1820   CHAR_INFO* CharInfo;
1821   NTSTATUS Status;
1822   DWORD SrcOffset;
1823   DWORD DstOffset;
1824   BOOLEAN DoFill;
1825
1826   ALIAS(ConsoleHandle,Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle);
1827   ALIAS(ScrollRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle);
1828   ALIAS(UseClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle);
1829   ALIAS(ClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle);
1830   ALIAS(DestinationOrigin,Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin);
1831   ALIAS(Fill,Request->Data.ScrollConsoleScreenBufferRequest.Fill);
1832
1833   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1834   Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1835   LOCK;
1836   Status = CsrGetObject( ProcessData, ConsoleHandle, (Object_t **)&Buff );
1837   if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1838   {
1839     Reply->Status = Status;
1840     UNLOCK;
1841     return Status;
1842   }
1843
1844   /* Make sure source rectangle is inside the screen buffer */
1845   CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1846   if (!CsrpGetIntersection(&SrcRegion, ScreenBuffer, ScrollRectangle))
1847     {
1848       UNLOCK;
1849       return (Reply->Status = STATUS_INVALID_PARAMETER);
1850     }
1851
1852   if (UseClipRectangle)
1853     {
1854       if (!CsrpGetIntersection(&SrcRegion, SrcRegion, ClipRectangle))
1855         {
1856           UNLOCK;
1857           return (Reply->Status = STATUS_SUCCESS);
1858         }
1859     }
1860
1861
1862   CsrpInitRect(
1863     DstRegion,
1864     DestinationOrigin.Y,
1865     DestinationOrigin.X,
1866     DestinationOrigin.Y + CsrpRectHeight(ScrollRectangle) - 1,
1867     DestinationOrigin.X + CsrpRectWidth(ScrollRectangle) - 1)
1868
1869   /* Make sure destination rectangle is inside the screen buffer */
1870   if (!CsrpGetIntersection(&DstRegion, DstRegion, ScreenBuffer))
1871     {
1872       UNLOCK;
1873       return (Reply->Status = STATUS_INVALID_PARAMETER);
1874     }
1875
1876   CsrpCopyRegion(Buff, SrcRegion, DstRegion);
1877
1878
1879   /* Get the region that should be filled with the specified character and attributes */
1880
1881   DoFill = FALSE;
1882
1883   CsrpGetUnion(&FillRegion, SrcRegion, DstRegion);
1884
1885   if (CsrpSubtractRect(&FillRegion, FillRegion, DstRegion))
1886     {
1887       /* FIXME: The subtracted rectangle is off by one line */
1888       FillRegion.Top += 1;
1889
1890       CsrpFillRegion(Buff, FillRegion, Fill);
1891       DoFill = TRUE;
1892     }
1893
1894   if (Buff == ActiveConsole->ActiveBuffer)
1895     {
1896       /* Draw destination region */
1897       CsrpDrawRegion(ActiveConsole->ActiveBuffer, DstRegion);
1898
1899       if (DoFill)
1900         {
1901           /* Draw filled region */
1902           CsrpDrawRegion(ActiveConsole->ActiveBuffer, FillRegion);
1903         }
1904     }
1905
1906   UNLOCK;
1907   return(Reply->Status = STATUS_SUCCESS);
1908 }
1909
1910
1911 CSR_API(CsrReadConsoleOutputChar)
1912 {
1913   NTSTATUS Status;
1914   PCSRSS_SCREEN_BUFFER ScreenBuffer;
1915   DWORD Xpos, Ypos;
1916   BYTE* ReadBuffer;
1917   DWORD i;
1918
1919   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1920   Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
1921   ReadBuffer = Reply->Data.ReadConsoleOutputCharReply.String;
1922
1923   LOCK;
1924
1925   Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
1926   if (!NT_SUCCESS(Status))
1927     {
1928       Reply->Status = Status;
1929       UNLOCK;
1930       return(Reply->Status);
1931     }
1932
1933   if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
1934     {
1935       Reply->Status = STATUS_INVALID_HANDLE;
1936       UNLOCK;
1937       return(Reply->Status);
1938     }
1939
1940   Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X + ScreenBuffer->ShowX;
1941   Ypos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + ScreenBuffer->ShowY;
1942
1943   for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
1944     {
1945       *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX)];
1946
1947       ReadBuffer++;
1948       Xpos++;
1949
1950       if (Xpos == ScreenBuffer->MaxX)
1951         {
1952           Xpos = 0;
1953           Ypos++;
1954
1955           if (Ypos == ScreenBuffer->MaxY)
1956             Ypos = 0;
1957         }
1958     }
1959
1960   *ReadBuffer = 0;
1961
1962   Reply->Status = STATUS_SUCCESS;
1963   Reply->Data.ReadConsoleOutputCharReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
1964   Reply->Data.ReadConsoleOutputCharReply.EndCoord.Y = Ypos - ScreenBuffer->ShowY;
1965   Reply->Header.MessageSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
1966   Reply->Header.DataSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
1967
1968   UNLOCK;
1969
1970   return(Reply->Status);
1971 }
1972
1973
1974 CSR_API(CsrReadConsoleOutputAttrib)
1975 {
1976   NTSTATUS Status;
1977   PCSRSS_SCREEN_BUFFER ScreenBuffer;
1978   DWORD Xpos, Ypos;
1979   CHAR* ReadBuffer;
1980   DWORD i;
1981
1982   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1983   Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
1984   ReadBuffer = Reply->Data.ReadConsoleOutputAttribReply.String;
1985
1986   LOCK;
1987
1988   Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
1989   if (!NT_SUCCESS(Status))
1990     {
1991       Reply->Status = Status;
1992       UNLOCK;
1993       return(Reply->Status);
1994     }
1995
1996   if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
1997     {
1998       Reply->Status = STATUS_INVALID_HANDLE;
1999       UNLOCK;
2000       return(Reply->Status);
2001     }
2002
2003   Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X + ScreenBuffer->ShowX;
2004   Ypos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + ScreenBuffer->ShowY;
2005
2006   for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2007     {
2008       *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX) + 1];
2009
2010       ReadBuffer++;
2011       Xpos++;
2012
2013       if (Xpos == ScreenBuffer->MaxX)
2014         {
2015           Xpos = 0;
2016           Ypos++;
2017
2018           if (Ypos == ScreenBuffer->MaxY)
2019             Ypos = 0;
2020         }
2021     }
2022
2023   *ReadBuffer = 0;
2024
2025   Reply->Status = STATUS_SUCCESS;
2026   Reply->Data.ReadConsoleOutputAttribReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
2027   Reply->Data.ReadConsoleOutputAttribReply.EndCoord.Y = Ypos - ScreenBuffer->ShowY;
2028   Reply->Header.MessageSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2029   Reply->Header.DataSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2030
2031   UNLOCK;
2032
2033   return(Reply->Status);
2034 }
2035
2036
2037 CSR_API(CsrGetNumberOfConsoleInputEvents)
2038 {
2039   NTSTATUS Status;
2040   PCSRSS_CONSOLE Console;
2041   PLIST_ENTRY CurrentItem;
2042   DWORD NumEvents;
2043   
2044   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2045   Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2046
2047   LOCK;
2048
2049   Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2050   if (!NT_SUCCESS(Status))
2051     {
2052       Reply->Status = Status;
2053       UNLOCK;
2054       return(Reply->Status);
2055     }
2056
2057   if (Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2058     {
2059       Reply->Status = STATUS_INVALID_HANDLE;
2060       UNLOCK;
2061       return(Reply->Status);
2062     }
2063   
2064   CurrentItem = &Console->InputEvents;
2065   NumEvents = 0;
2066   
2067   // If there are any events ...
2068   if(CurrentItem->Flink != CurrentItem)
2069   {
2070     do
2071     {
2072       CurrentItem = CurrentItem->Flink;
2073       ++NumEvents;
2074     }while(CurrentItem != &Console->InputEvents);
2075   }
2076   
2077   UNLOCK;
2078   
2079   Reply->Status = STATUS_SUCCESS;
2080   Reply->Data.GetNumInputEventsReply.NumInputEvents = NumEvents;
2081    
2082   return Reply->Status;
2083 }
2084
2085
2086 CSR_API(CsrPeekConsoleInput)
2087 {
2088    NTSTATUS Status;
2089    PCSRSS_CONSOLE Console;
2090    DWORD Size;
2091    DWORD Length;
2092    PLIST_ENTRY CurrentItem;
2093    PLIST_ENTRY NextItem;
2094    PINPUT_RECORD InputRecord;
2095    ConsoleInput* Item;
2096    UINT NumItems;
2097    
2098    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2099    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2100    
2101    LOCK;
2102    
2103    Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2104    if(!NT_SUCCESS(Status))
2105    {
2106       Reply->Status = Status;
2107       UNLOCK;
2108       return Reply->Status;
2109    }
2110
2111    if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2112    {
2113       Reply->Status = STATUS_INVALID_HANDLE;
2114       UNLOCK;
2115       return Reply->Status;
2116    }
2117    
2118    InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2119    Length = Request->Data.PeekConsoleInputRequest.Length;
2120    Size = Length * sizeof(INPUT_RECORD);
2121    
2122     if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2123          || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2124    {
2125       UNLOCK;
2126       Reply->Status = STATUS_ACCESS_VIOLATION;
2127       return Reply->Status ;
2128    }
2129    
2130    NumItems = 0;
2131    
2132    if(!IsListEmpty(&Console->InputEvents))
2133    {
2134       CurrentItem = &Console->InputEvents;
2135    
2136       while(NumItems < Length)
2137       {
2138          ++NumItems;
2139          Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2140          *InputRecord++ = Item->InputEvent;
2141          
2142          if(CurrentItem->Flink == &Console->InputEvents)
2143             break;
2144          else
2145             CurrentItem = CurrentItem->Flink;
2146       }
2147    }
2148
2149    UNLOCK;
2150    
2151    Reply->Status = STATUS_SUCCESS;
2152    Reply->Data.PeekConsoleInputReply.Length = NumItems;
2153    return Reply->Status;
2154 }
2155
2156
2157 CSR_API(CsrReadConsoleOutput)
2158 {
2159    PCHAR_INFO CharInfo;
2160    PCHAR_INFO CurCharInfo;
2161    PCSRSS_SCREEN_BUFFER ScreenBuffer;
2162    DWORD Size;
2163    DWORD Length;
2164    DWORD SizeX, SizeY;
2165    NTSTATUS Status;
2166    COORD BufferSize;
2167    COORD BufferCoord;
2168    SMALL_RECT ReadRegion;
2169    SMALL_RECT ScreenRect;
2170    DWORD i, Y, X, Offset;
2171       
2172    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2173    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2174   
2175    LOCK;
2176   
2177    Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2178    if(!NT_SUCCESS(Status))
2179    {
2180       Reply->Status = Status;
2181       UNLOCK;
2182       return Reply->Status;
2183    }
2184
2185    if(ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2186    {
2187       Reply->Status = STATUS_INVALID_HANDLE;
2188       UNLOCK;
2189       return Reply->Status;
2190    }
2191    
2192    CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
2193    ReadRegion = Request->Data.ReadConsoleOutputRequest.ReadRegion;
2194    BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
2195    BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
2196    Length = BufferSize.X * BufferSize.Y;
2197    Size = Length * sizeof(INPUT_RECORD);
2198    
2199     if(((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
2200          || (((PVOID)CharInfo + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2201    {
2202       UNLOCK;
2203       Reply->Status = STATUS_ACCESS_VIOLATION;
2204       return Reply->Status ;
2205    }
2206    
2207    SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(ReadRegion));
2208    SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(ReadRegion));
2209    ReadRegion.Bottom = ReadRegion.Top + SizeY;
2210    ReadRegion.Right = ReadRegion.Left + SizeX;
2211
2212    CsrpInitRect(ScreenRect, 0, 0, ScreenBuffer->MaxY - 1, ScreenBuffer->MaxX - 1);
2213    if (!CsrpGetIntersection(&ReadRegion, ScreenRect, ReadRegion))
2214    {
2215       UNLOCK;
2216       Reply->Status = STATUS_SUCCESS;
2217       return Reply->Status;
2218    }
2219    
2220    for(i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
2221    {
2222      CurCharInfo = CharInfo + (i * BufferSize.Y);
2223      
2224      Offset = (Y * ScreenBuffer->MaxX + ReadRegion.Left) * 2;
2225      for(X = ReadRegion.Left; X < ReadRegion.Right; ++X)
2226      {
2227         CurCharInfo->Char.AsciiChar = GET_CELL_BUFFER(ScreenBuffer, Offset);
2228         CurCharInfo->Attributes = GET_CELL_BUFFER(ScreenBuffer, Offset);
2229         ++CurCharInfo;
2230      }
2231   }
2232   
2233    UNLOCK;
2234    
2235    Reply->Status = STATUS_SUCCESS;
2236    Reply->Data.ReadConsoleOutputReply.ReadRegion.Right = ReadRegion.Left + SizeX - 1;
2237    Reply->Data.ReadConsoleOutputReply.ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
2238    Reply->Data.ReadConsoleOutputReply.ReadRegion.Left = ReadRegion.Left;
2239    Reply->Data.ReadConsoleOutputReply.ReadRegion.Top = ReadRegion.Top;
2240    
2241    return Reply->Status;
2242 }
2243
2244
2245 CSR_API(CsrWriteConsoleInput)
2246 {
2247    PINPUT_RECORD InputRecord;
2248    PCSRSS_CONSOLE Console;
2249    NTSTATUS Status;
2250    DWORD Length;
2251    DWORD Size;
2252    DWORD i;
2253    PLIST_ENTRY NextItem;
2254    ConsoleInput* Record;
2255    
2256    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2257    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2258    
2259    LOCK;
2260    
2261    Status = CsrGetObject(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, (Object_t**)&Console);
2262    if(!NT_SUCCESS(Status))
2263    {
2264       Reply->Status = Status;
2265       UNLOCK;
2266       return Reply->Status;
2267    }
2268
2269    if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2270    {
2271       Reply->Status = STATUS_INVALID_HANDLE;
2272       UNLOCK;
2273       return Reply->Status;
2274    }
2275    
2276    InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
2277    Length = Request->Data.WriteConsoleInputRequest.Length;
2278    Size = Length * sizeof(INPUT_RECORD);
2279    
2280     if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2281          || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2282    {
2283       UNLOCK;
2284       Reply->Status = STATUS_ACCESS_VIOLATION;
2285       return Reply->Status ;
2286    }
2287    
2288    for(i = 0; i < Length; ++i)
2289    {
2290       Record = RtlAllocateHeap(CsrssApiHeap, 0, sizeof(ConsoleInput));
2291       if(Record == NULL)
2292       {
2293          UNLOCK;
2294          Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
2295          return Reply->Status;
2296       }
2297       
2298       Record->InputEvent = *InputRecord++;
2299       InsertTailList(&Console->InputEvents, &Record->ListEntry);
2300    }
2301       
2302    UNLOCK;
2303    
2304    Reply->Status = STATUS_SUCCESS;
2305    Reply->Data.WriteConsoleInputReply.Length = i;
2306    return Reply->Status;
2307 }
2308
2309 /* EOF */