update for HEAD-2003050101
[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
50    if (ProcessData == NULL)
51    {
52      return(Reply->Status = STATUS_INVALID_PARAMETER);
53    }
54
55    if( ProcessData->Console )
56       {
57          Reply->Status = STATUS_INVALID_PARAMETER;
58          return STATUS_INVALID_PARAMETER;
59       }
60    Reply->Status = STATUS_SUCCESS;
61    Console = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_CONSOLE ) );
62    if( Console == 0 )
63       {
64         Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
65         return STATUS_INSUFFICIENT_RESOURCES;
66       }
67    Reply->Status = CsrInitConsole( Console );
68    if( !NT_SUCCESS( Reply->Status ) )
69      {
70        RtlFreeHeap( CsrssApiHeap, 0, Console );
71        return Reply->Status;
72      }
73    ProcessData->Console = Console;
74    /* add a reference count because the process is tied to the console */
75    Console->Header.ReferenceCount++;
76    Status = CsrInsertObject( ProcessData, &Reply->Data.AllocConsoleReply.InputHandle, &Console->Header );
77    if( !NT_SUCCESS( Status ) )
78       {
79          CsrDeleteConsole( Console );
80          ProcessData->Console = 0;
81          return Reply->Status = Status;
82       }
83    Status = CsrInsertObject( ProcessData, &Reply->Data.AllocConsoleReply.OutputHandle, &Console->ActiveBuffer->Header );
84    if( !NT_SUCCESS( Status ) )
85       {
86          Console->Header.ReferenceCount--;
87          CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
88          ProcessData->Console = 0;
89          return Reply->Status = Status;
90       }
91    ClientId.UniqueProcess = (HANDLE)ProcessData->ProcessId;
92    Status = NtOpenProcess( &Process, PROCESS_DUP_HANDLE, 0, &ClientId );
93    if( !NT_SUCCESS( Status ) )
94      {
95        DbgPrint( "CSR: NtOpenProcess() failed for handle duplication\n" );
96        Console->Header.ReferenceCount--;
97        ProcessData->Console = 0;
98        CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.OutputHandle );
99        CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
100        Reply->Status = Status;
101        return Status;
102      }
103    Status = NtDuplicateObject( NtCurrentProcess(), ProcessData->Console->ActiveEvent, Process, &ProcessData->ConsoleEvent, SYNCHRONIZE, FALSE, 0 );
104    if( !NT_SUCCESS( Status ) )
105      {
106        DbgPrint( "CSR: NtDuplicateObject() failed: %x\n", Status );
107        NtClose( Process );
108        Console->Header.ReferenceCount--;
109        CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.OutputHandle );
110        CsrReleaseObject( ProcessData, Reply->Data.AllocConsoleReply.InputHandle );
111        ProcessData->Console = 0;
112        Reply->Status = Status;
113        return Status;
114      }
115    NtClose( Process );
116    return STATUS_SUCCESS;
117 }
118
119 CSR_API(CsrFreeConsole)
120 {
121    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
122    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
123      sizeof(LPC_MESSAGE);
124
125    if (ProcessData == NULL)
126    {
127      return(Reply->Status = STATUS_INVALID_PARAMETER);
128    }
129
130    Reply->Status = STATUS_NOT_IMPLEMENTED;
131    
132    return(STATUS_NOT_IMPLEMENTED);
133 }
134
135 CSR_API(CsrReadConsole)
136 {
137    PLIST_ENTRY CurrentEntry;
138    ConsoleInput *Input;
139    PCHAR Buffer;
140    int   i = 0;
141    ULONG nNumberOfCharsToRead;
142    PCSRSS_CONSOLE Console;
143    NTSTATUS Status;
144    
145    /* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
146    nNumberOfCharsToRead = Request->Data.ReadConsoleRequest.NrCharactersToRead > CSRSS_MAX_READ_CONSOLE_REQUEST ? CSRSS_MAX_READ_CONSOLE_REQUEST : Request->Data.ReadConsoleRequest.NrCharactersToRead;
147    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
148    Reply->Header.DataSize = Reply->Header.MessageSize -
149      sizeof(LPC_MESSAGE);
150
151    Buffer = Reply->Data.ReadConsoleReply.Buffer;
152    LOCK;   
153    Status = CsrGetObject( ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle, (Object_t **)&Console );
154    if( !NT_SUCCESS( Status ) )
155       {
156          Reply->Status = Status;
157          UNLOCK;
158          return Status;
159       }
160    if( Console->Header.Type != CSRSS_CONSOLE_MAGIC )
161       {
162          Reply->Status = STATUS_INVALID_HANDLE;
163          UNLOCK;
164          return STATUS_INVALID_HANDLE;
165       }
166    Reply->Data.ReadConsoleReply.EventHandle = ProcessData->ConsoleEvent;
167    for (; i<nNumberOfCharsToRead && Console->InputEvents.Flink != &Console->InputEvents; i++ )     
168       {
169          // remove input event from queue
170         CurrentEntry = RemoveHeadList(&Console->InputEvents);
171         Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
172
173          // only pay attention to valid ascii chars, on key down
174          if( Input->InputEvent.EventType == KEY_EVENT &&
175              Input->InputEvent.Event.KeyEvent.bKeyDown == TRUE &&
176              Input->InputEvent.Event.KeyEvent.uChar.AsciiChar )
177             {
178                // backspace handling
179                if( Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' )
180                   {
181                      // echo if it has not already been done, and either we or the client has chars to be deleted
182                      if( !Input->Echoed && ( i || Request->Data.ReadConsoleRequest.nCharsCanBeDeleted ) )
183                         CsrpWriteConsole( Console->ActiveBuffer, &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
184                      if( i )
185                         i-=2;        // if we already have something to return, just back it up by 2
186                      else
187                         {            // otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer
188                            Reply->Data.ReadConsoleReply.NrCharactersRead = 0;
189                            Reply->Status = STATUS_NOTIFY_CLEANUP;
190                            Console->WaitingChars--;
191                            RtlFreeHeap( CsrssApiHeap, 0, Input );
192                            UNLOCK;
193                            return STATUS_NOTIFY_CLEANUP;
194                         }
195                      Request->Data.ReadConsoleRequest.nCharsCanBeDeleted--;
196                      Input->Echoed = TRUE;   // mark as echoed so we don't echo it below
197                   }
198                // do not copy backspace to buffer
199                else Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar;
200                // echo to screen if enabled and we did not already echo the char
201                if( Console->Mode & ENABLE_ECHO_INPUT &&
202                    !Input->Echoed &&
203                    Input->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
204                   CsrpWriteConsole( Console->ActiveBuffer, &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
205             }
206          else i--;
207          Console->WaitingChars--;
208          RtlFreeHeap( CsrssApiHeap, 0, Input );
209       }
210    Reply->Data.ReadConsoleReply.NrCharactersRead = i;
211    if( !i )
212       Reply->Status = STATUS_PENDING;    // we didn't read anything
213    else if( Console->Mode & ENABLE_LINE_INPUT )
214       if( !Console->WaitingLines || Buffer[i-1] != '\n' )
215          {
216             Reply->Status = STATUS_PENDING; // line buffered, didn't get a complete line
217          }
218       else {
219          Console->WaitingLines--;
220          Reply->Status = STATUS_SUCCESS; // line buffered, did get a complete line
221       }
222    else Reply->Status = STATUS_SUCCESS;  // not line buffered, did read something
223    if( Reply->Status == STATUS_PENDING )
224       {
225          Console->EchoCount = nNumberOfCharsToRead - i;
226       }
227    else {
228       Console->EchoCount = 0;             // if the client is no longer waiting on input, do not echo
229    }
230    Reply->Header.MessageSize += i;
231    UNLOCK;
232    return Reply->Status;
233 }
234
235 #define GET_CELL_BUFFER(b,o)\
236 (b)->Buffer[(o)++];
237
238 #define SET_CELL_BUFFER(b,o,c,a)\
239 (b)->Buffer[(o)++]=(c);\
240 (b)->Buffer[(o)++]=(a);
241
242 static VOID FASTCALL
243 ClearLineBuffer (
244         PCSRSS_SCREEN_BUFFER    Buff,
245         DWORD                   StartX
246         )
247 {
248         DWORD Offset   = 2 * ((Buff->CurrentY * Buff->MaxX) + StartX);
249         
250         for ( ; StartX < Buff->MaxX; StartX ++ )
251         {
252                 /* Fill the cell: Offset is incremented by the macro */
253                 SET_CELL_BUFFER(Buff,Offset,' ',Buff->DefaultAttrib)
254         }
255 }
256
257 NTSTATUS STDCALL CsrpWriteConsole( PCSRSS_SCREEN_BUFFER Buff, CHAR *Buffer, DWORD Length, BOOL Attrib )
258 {
259    IO_STATUS_BLOCK Iosb;
260    NTSTATUS Status;
261    int i;
262    DWORD Offset;
263    
264    for( i = 0; i < Length; i++ )
265       {
266          switch( Buffer[ i ] )
267             {
268             /* --- LF --- */
269             case '\n':
270                Buff->CurrentX = 0;
271                /* slide the viewable screen */
272                if (((Buff->CurrentY-Buff->ShowY + Buff->MaxY) % Buff->MaxY) == PhysicalConsoleSize.Y - 1)
273                  if (++Buff->ShowY == Buff->MaxY)
274                    Buff->ShowY = 0;
275                if( ++Buff->CurrentY == Buff->MaxY )
276                   {
277                      Buff->CurrentY = 0;
278                   }
279                ClearLineBuffer (Buff, 0);
280                break;
281             /* --- BS --- */
282             case '\b':
283               if( Buff->CurrentX == 0 )
284                 {
285                   /* slide viewable screen up */
286                   if( Buff->ShowY == Buff->CurrentY )
287                     {
288                       if( Buff->ShowY == 0 )
289                         Buff->ShowY = Buff->MaxY;
290                       else
291                         Buff->ShowY--;
292                     }
293                   /* slide virtual position up */
294                   Buff->CurrentX = Buff->MaxX;
295                   if( Buff->CurrentY == 0 )
296                     Buff->CurrentY = Buff->MaxY;
297                   else
298                     Buff->CurrentY--;
299                 }
300               else
301                 Buff->CurrentX--;
302               Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + Buff->CurrentX);
303               SET_CELL_BUFFER(Buff,Offset,' ',Buff->DefaultAttrib);
304               break;
305             /* --- CR --- */
306             case '\r':
307               Buff->CurrentX = 0;
308               break;
309             /* --- TAB --- */
310             case '\t':
311               CsrpWriteConsole(Buff, "        ", (8 - (Buff->CurrentX % 8)), FALSE);
312               break;
313             /* --- */
314             default:
315                Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
316                Buff->Buffer[Offset ++] = Buffer[ i ];
317                if( Attrib )
318                   Buff->Buffer[Offset] = Buff->DefaultAttrib;
319                Buff->CurrentX++;
320                if( Buff->CurrentX == Buff->MaxX )
321                   {
322                      /* if end of line, go to next */
323                      Buff->CurrentX = 0;
324                      if( ++Buff->CurrentY == Buff->MaxY )
325                         {
326                            /* if end of buffer, wrap back to beginning */
327                            Buff->CurrentY = 0;
328                         }
329                      /* clear new line */
330                      ClearLineBuffer (Buff, 0);
331                      /* slide the viewable screen */
332                      if( (Buff->CurrentY - Buff->ShowY + Buff->MaxY - 1) % Buff->MaxY == PhysicalConsoleSize.Y -1)
333                        if( ++Buff->ShowY == Buff->MaxY )
334                          Buff->ShowY = 0;
335                   }
336             }
337       }
338    if( Buff == ActiveConsole->ActiveBuffer )
339      {    /* only write to screen if Console is Active, and not scrolled up */
340         if( Attrib )
341            {
342               Status = NtWriteFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, Buffer, Length, NULL, 0);
343               if (!NT_SUCCESS(Status))
344                  DbgPrint("CSR: Write failed\n");
345            }
346       }
347    return(STATUS_SUCCESS);
348 }
349
350 #define CsrpInitRect(_Rect, _Top, _Left, _Bottom, _Right) \
351 { \
352   ((_Rect).Top) = _Top; \
353   ((_Rect).Left) = _Left; \
354   ((_Rect).Bottom) = _Bottom; \
355   ((_Rect).Right) = _Right; \
356 }
357
358 #define CsrpRectHeight(Rect) \
359     ((Rect.Top) > (Rect.Bottom) ? 0 : (Rect.Bottom) - (Rect.Top) + 1)
360
361 #define CsrpRectWidth(Rect) \
362     ((Rect.Left) > (Rect.Right) ? 0 : (Rect.Right) - (Rect.Left) + 1)
363
364 #define CsrpIsRectEmpty(Rect) \
365   ((Rect.Left > Rect.Right) || (Rect.Top > Rect.Bottom))
366
367
368 inline BOOLEAN CsrpIsEqualRect(
369   SMALL_RECT Rect1,
370   SMALL_RECT Rect2)
371 {
372   return ((Rect1.Left == Rect2.Left) && (Rect1.Right == Rect2.Right) &&
373           (Rect1.Top == Rect2.Top) && (Rect1.Bottom == Rect2.Bottom));
374 }
375
376 inline BOOLEAN CsrpGetIntersection(
377   PSMALL_RECT Intersection,
378   SMALL_RECT Rect1,
379   SMALL_RECT Rect2)
380 {
381   if (CsrpIsRectEmpty(Rect1) ||
382     (CsrpIsRectEmpty(Rect2)) ||
383     (Rect1.Top > Rect2.Bottom) ||
384     (Rect1.Left > Rect2.Right) ||
385     (Rect1.Bottom < Rect2.Top) ||
386     (Rect1.Right < Rect2.Left))
387   {
388     /* The rectangles do not intersect */
389     CsrpInitRect(*Intersection, 0, -1, 0, -1)
390     return FALSE;
391   }
392
393   CsrpInitRect(
394     *Intersection,
395     RtlMax(Rect1.Top, Rect2.Top),
396     RtlMax(Rect1.Left, Rect2.Left),
397     RtlMin(Rect1.Bottom, Rect2.Bottom),
398     RtlMin(Rect1.Right, Rect2.Right));
399   return TRUE;
400 }
401
402 inline BOOLEAN CsrpGetUnion(
403   PSMALL_RECT Union,
404   SMALL_RECT Rect1,
405   SMALL_RECT Rect2)
406 {
407   if (CsrpIsRectEmpty(Rect1))
408     {
409             if (CsrpIsRectEmpty(Rect2))
410             {
411               CsrpInitRect(*Union, 0, -1, 0, -1);
412               return FALSE;
413             }
414           else
415       *Union = Rect2;
416     }
417   else
418     {
419             if (CsrpIsRectEmpty(Rect2))
420         {
421         *Union = Rect1;
422         }
423             else
424               {
425           CsrpInitRect(
426             *Union,
427             RtlMin(Rect1.Top, Rect2.Top),
428             RtlMin(Rect1.Left, Rect2.Left),
429             RtlMax(Rect1.Bottom, Rect2.Bottom),
430             RtlMax(Rect1.Right, Rect2.Right));
431               }
432     }
433   return TRUE;
434 }
435
436 inline BOOLEAN CsrpSubtractRect(
437   PSMALL_RECT Subtraction,
438   SMALL_RECT Rect1,
439   SMALL_RECT Rect2)
440 {
441   SMALL_RECT tmp;
442
443   if (CsrpIsRectEmpty(Rect1))
444     {
445             CsrpInitRect(*Subtraction, 0, -1, 0, -1);
446             return FALSE;
447     }
448   *Subtraction = Rect1;
449   if (CsrpGetIntersection(&tmp, Rect1, Rect2))
450     {
451             if (CsrpIsEqualRect(tmp, *Subtraction))
452               {
453                 CsrpInitRect(*Subtraction, 0, -1, 0, -1);
454                 return FALSE;
455               }
456             if ((tmp.Top == Subtraction->Top) && (tmp.Bottom == Subtraction->Bottom))
457               {
458                 if (tmp.Left == Subtraction->Left)
459             Subtraction->Left = tmp.Right;
460                 else if (tmp.Right == Subtraction->Right)
461             Subtraction->Right = tmp.Left;
462               }
463             else if ((tmp.Left == Subtraction->Left) && (tmp.Right == Subtraction->Right))
464               {
465                 if (tmp.Top == Subtraction->Top)
466             Subtraction->Top = tmp.Bottom;
467                 else if (tmp.Bottom == Subtraction->Bottom)
468             Subtraction->Bottom = tmp.Top;
469               }
470     }
471   return TRUE;
472 }
473
474 /*
475  * Screen buffer must be locked when this function is called
476  */
477 static VOID CsrpCopyRegion(
478   PCSRSS_SCREEN_BUFFER ScreenBuffer,
479   SMALL_RECT SrcRegion,
480   SMALL_RECT DstRegion)
481 {
482   SHORT SrcY, DstY;
483   DWORD SrcOffset;
484   DWORD DstOffset;
485   DWORD BytesPerLine;
486   ULONG i;
487
488   DstY = DstRegion.Top;
489   BytesPerLine = CsrpRectWidth(DstRegion) * 2;
490
491   SrcY = (SrcRegion.Top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
492   DstY = (DstRegion.Top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
493   SrcOffset = (SrcY * ScreenBuffer->MaxX + SrcRegion.Left + ScreenBuffer->ShowX) * 2;
494   DstOffset = (DstY * ScreenBuffer->MaxX + DstRegion.Left + ScreenBuffer->ShowX) * 2;
495   
496   for (i = SrcRegion.Top; i <= SrcRegion.Bottom; i++)
497   {
498     RtlCopyMemory(
499       &ScreenBuffer->Buffer[DstOffset],
500       &ScreenBuffer->Buffer[SrcOffset],
501       BytesPerLine);
502
503     if (++DstY == ScreenBuffer->MaxY)
504     {
505       DstY = 0;
506       DstOffset = (DstRegion.Left + ScreenBuffer->ShowX) * 2;
507     }
508     else
509     {
510       DstOffset += ScreenBuffer->MaxX * 2;
511     }
512
513     if (++SrcY == ScreenBuffer->MaxY)
514     {
515       SrcY = 0;
516       SrcOffset = (SrcRegion.Left + ScreenBuffer->ShowX) * 2;
517     }
518     else
519     {
520       SrcOffset += ScreenBuffer->MaxX * 2;
521     }
522   }
523 }
524
525 /*
526  * Screen buffer must be locked when this function is called
527  */
528 static VOID CsrpFillRegion(
529   PCSRSS_SCREEN_BUFFER ScreenBuffer,
530   SMALL_RECT Region,
531   CHAR_INFO CharInfo)
532 {
533   SHORT X, Y;
534   DWORD Offset;
535   DWORD Delta;
536   ULONG i;
537
538   Y = (Region.Top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
539   Offset = (Y * ScreenBuffer->MaxX + Region.Left + ScreenBuffer->ShowX) * 2;
540   Delta = (ScreenBuffer->MaxX - CsrpRectWidth(Region)) * 2;
541
542   for (i = Region.Top; i <= Region.Bottom; i++)
543   {
544     for (X = Region.Left; X <= Region.Right; X++)
545     {
546       SET_CELL_BUFFER(ScreenBuffer, Offset, CharInfo.Char.AsciiChar, CharInfo.Attributes);
547     }
548     if (++Y == ScreenBuffer->MaxY)
549     {
550       Y = 0;
551       Offset = (Region.Left + ScreenBuffer->ShowX) * 2;
552     }
553     else
554     {
555       Offset += Delta;
556     }
557   }
558 }
559
560 /*
561  * Screen buffer must be locked when this function is called
562  */
563 inline NTSTATUS CsrpSetConsoleDeviceCursor(PCSRSS_SCREEN_BUFFER ScreenBuffer, SHORT X, SHORT Y)
564 {
565    CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
566    IO_STATUS_BLOCK Iosb;
567
568    ScrInfo.dwCursorPosition.X = X;
569    ScrInfo.dwCursorPosition.Y = Y;
570    ScrInfo.wAttributes = ScreenBuffer->DefaultAttrib;
571
572    return NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
573      IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
574 }
575
576 /*
577  * Region - Region of virtual screen buffer to draw onto the physical console
578  * Screen buffer must be locked when this function is called
579  */
580 static VOID CsrpDrawRegion(
581   PCSRSS_SCREEN_BUFFER ScreenBuffer,
582   SMALL_RECT Region)
583 {
584    IO_STATUS_BLOCK Iosb;
585    NTSTATUS Status;
586    CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
587    CONSOLE_MODE Mode;
588    int i, y;
589    DWORD BytesPerLine;
590    DWORD SrcOffset;
591    DWORD SrcDelta;
592
593    Mode.dwMode = 0; /* clear ENABLE_PROCESSED_OUTPUT mode */
594    Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
595      IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
596    if( !NT_SUCCESS( Status ) )
597      {
598        DbgPrint( "CSR: Failed to set console mode\n" );
599        return;
600      }
601
602    /* blast out buffer */
603    BytesPerLine = CsrpRectWidth(Region) * 2;
604    SrcOffset = (((Region.Top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY) * ScreenBuffer->MaxX + Region.Left + ScreenBuffer->ShowX) * 2;
605    SrcDelta = ScreenBuffer->MaxX * 2;
606    for( i = Region.Top, y = ScreenBuffer->ShowY; i <= Region.Bottom; i++ )
607      {
608         /* Position the cursor correctly */
609         Status = CsrpSetConsoleDeviceCursor(ScreenBuffer, Region.Left, i);
610         if( !NT_SUCCESS( Status ) )
611           {
612             DbgPrint( "CSR: Failed to set console info\n" );
613             return;
614           }
615
616         Status = NtWriteFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
617          &ScreenBuffer->Buffer[ SrcOffset ],
618          BytesPerLine, 0, 0 );
619        if( !NT_SUCCESS( Status ) )
620               {
621                 DbgPrint( "CSR: Write to console failed\n" );
622                 return;
623               }
624
625        /* wrap back around the end of the buffer */
626        if( ++y == ScreenBuffer->MaxY )
627        {
628          y = 0;
629          SrcOffset = (Region.Left + ScreenBuffer->ShowX) * 2;
630        }
631        else
632        {
633          SrcOffset += SrcDelta;
634        }
635      }
636    Mode.dwMode = ENABLE_PROCESSED_OUTPUT;
637    Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
638      IOCTL_CONSOLE_SET_MODE, &Mode, sizeof( Mode ), 0, 0 );
639    if( !NT_SUCCESS( Status ) )
640      {
641        DbgPrint( "CSR: Failed to set console mode\n" );
642        return;
643      }
644    Status = CsrpSetConsoleDeviceCursor(
645      ScreenBuffer,
646      ScreenBuffer->CurrentX - ScreenBuffer->ShowX,
647      ((ScreenBuffer->CurrentY + ScreenBuffer->MaxY) - ScreenBuffer->ShowY) % ScreenBuffer->MaxY);
648    if( !NT_SUCCESS( Status ) )
649      {
650        DbgPrint( "CSR: Failed to set console info\n" );
651        return;
652      }
653    Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
654      IOCTL_CONSOLE_SET_CURSOR_INFO, &ScreenBuffer->CursorInfo,
655      sizeof( ScreenBuffer->CursorInfo ), 0, 0 );
656    if( !NT_SUCCESS( Status ) )
657      {
658        DbgPrint( "CSR: Failed to set cursor info\n" );
659        return;
660      }
661 }
662
663
664 CSR_API(CsrWriteConsole)
665 {
666    BYTE *Buffer = Request->Data.WriteConsoleRequest.Buffer;
667    PCSRSS_SCREEN_BUFFER Buff;
668
669    DPRINT("CsrWriteConsole\n");
670    
671    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
672    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
673      sizeof(LPC_MESSAGE);
674
675    LOCK;
676    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle,
677      (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
678       {
679          UNLOCK;
680          return Reply->Status = STATUS_INVALID_HANDLE;
681       }
682    CsrpWriteConsole( Buff, Buffer, Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE );
683    UNLOCK;
684    return Reply->Status = STATUS_SUCCESS;
685 }
686
687
688 NTSTATUS STDCALL CsrInitConsoleScreenBuffer( PCSRSS_SCREEN_BUFFER Console )
689 {
690   Console->Header.Type = CSRSS_SCREEN_BUFFER_MAGIC;
691   Console->Header.ReferenceCount = 0;
692   Console->MaxX = PhysicalConsoleSize.X;
693   Console->MaxY = PhysicalConsoleSize.Y;
694   Console->ShowX = 0;
695   Console->ShowY = 0;
696   Console->CurrentX = 0;
697   Console->CurrentY = 0;
698   Console->Buffer = RtlAllocateHeap( CsrssApiHeap, 0, Console->MaxX * Console->MaxY * 2 );
699   if( Console->Buffer == 0 )
700     return STATUS_INSUFFICIENT_RESOURCES;
701   Console->DefaultAttrib = 0x17;
702   /* initialize buffer to be empty with default attributes */
703   for( ; Console->CurrentY < Console->MaxY; Console->CurrentY++ )
704     {
705             ClearLineBuffer (Console, 0);
706     }
707   Console->CursorInfo.bVisible = TRUE;
708   Console->CursorInfo.dwSize = 5;
709   Console->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
710   Console->CurrentX = 0;
711   Console->CurrentY = 0;
712   return STATUS_SUCCESS;
713 }
714
715 VOID STDCALL CsrDeleteScreenBuffer( PCSRSS_SCREEN_BUFFER Buffer )
716 {
717   RtlFreeHeap( CsrssApiHeap, 0, Buffer->Buffer );
718   RtlFreeHeap( CsrssApiHeap, 0, Buffer );
719 }
720
721 NTSTATUS STDCALL CsrInitConsole(PCSRSS_CONSOLE Console)
722 {
723   NTSTATUS Status;
724   OBJECT_ATTRIBUTES ObjectAttributes;
725
726   Console->Title.MaximumLength = Console->Title.Length = 0;
727   Console->Title.Buffer = 0;
728   
729   RtlCreateUnicodeString( &Console->Title, L"Command Prompt" );
730   
731   Console->Header.ReferenceCount = 0;
732   Console->WaitingChars = 0;
733   Console->WaitingLines = 0;
734   Console->EchoCount = 0;
735   Console->Header.Type = CSRSS_CONSOLE_MAGIC;
736   Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
737   Console->EarlyReturn = FALSE;
738   InitializeListHead(&Console->InputEvents);
739
740   InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_INHERIT, NULL, NULL);
741
742   Status = NtCreateEvent( &Console->ActiveEvent, STANDARD_RIGHTS_ALL, &ObjectAttributes, FALSE, FALSE );
743   if( !NT_SUCCESS( Status ) )
744     {
745       return Status;
746     }
747   Console->ActiveBuffer = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
748   if( !Console->ActiveBuffer )
749      {
750         NtClose( Console->ActiveEvent );
751         return STATUS_INSUFFICIENT_RESOURCES;
752      }
753   Status = CsrInitConsoleScreenBuffer( Console->ActiveBuffer );
754   if( !NT_SUCCESS( Status ) )
755      {
756         NtClose( Console->ActiveEvent );
757         RtlFreeHeap( CsrssApiHeap, 0, Console->ActiveBuffer );
758         return Status;
759      }
760   /* add a reference count because the buffer is tied to the console */
761   Console->ActiveBuffer->Header.ReferenceCount++;
762   /* make console active, and insert into console list */
763   LOCK;
764   if( ActiveConsole )
765      {
766         Console->Prev = ActiveConsole;
767         Console->Next = ActiveConsole->Next;
768         ActiveConsole->Next->Prev = Console;
769         ActiveConsole->Next = Console;
770      }
771   else {
772      Console->Prev = Console;
773      Console->Next = Console;
774   }
775   ActiveConsole = Console;
776   /* copy buffer contents to screen */
777   CsrDrawConsole( Console->ActiveBuffer );
778   UNLOCK;
779   return STATUS_SUCCESS;
780 }
781
782 /***************************************************************
783  *  CsrDrawConsole blasts the console buffer onto the screen   *
784  *  must be called while holding the active console lock       *
785  **************************************************************/
786 VOID STDCALL CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff )
787 {
788    SMALL_RECT Region;
789
790    CsrpInitRect(
791      Region,
792      0,
793      0,
794      PhysicalConsoleSize.Y - 1,
795      PhysicalConsoleSize.X - 1);
796
797    CsrpDrawRegion(Buff, Region);
798 }
799
800
801 VOID STDCALL CsrDeleteConsole( PCSRSS_CONSOLE Console )
802 {
803    ConsoleInput *Event;
804    DPRINT( "CsrDeleteConsole\n" );
805    LOCK;
806    /* Drain input event queue */
807    while( Console->InputEvents.Flink != &Console->InputEvents )
808       {
809          Event = (ConsoleInput *)Console->InputEvents.Flink;
810          Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
811          Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
812          RtlFreeHeap( CsrssApiHeap, 0, Event );
813       }
814    /* Switch to next console */
815    if( ActiveConsole == Console )
816       {
817          if( Console->Next != Console )
818             {
819                ActiveConsole = Console->Next;
820             }
821          else ActiveConsole = 0;
822       }
823    if (Console->Next != Console)
824    {
825       Console->Prev->Next = Console->Next;
826       Console->Next->Prev = Console->Prev;
827    }
828    
829    if( ActiveConsole )
830      CsrDrawConsole( ActiveConsole->ActiveBuffer );
831    if( !--Console->ActiveBuffer->Header.ReferenceCount )
832      CsrDeleteScreenBuffer( Console->ActiveBuffer );
833    UNLOCK;
834    NtClose( Console->ActiveEvent );
835    RtlFreeUnicodeString( &Console->Title );
836    RtlFreeHeap( CsrssApiHeap, 0, Console );
837 }
838
839 VOID STDCALL CsrInitConsoleSupport(VOID)
840 {
841    OBJECT_ATTRIBUTES ObjectAttributes;
842    UNICODE_STRING DeviceName;
843    NTSTATUS Status;
844    IO_STATUS_BLOCK Iosb;
845    CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
846    
847    DPRINT("CSR: CsrInitConsoleSupport()\n");
848    
849    RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\BlueScreen");
850    InitializeObjectAttributes(&ObjectAttributes,
851                               &DeviceName,
852                               0,
853                               NULL,
854                               NULL);
855    Status = NtOpenFile(&ConsoleDeviceHandle,
856                        FILE_ALL_ACCESS,
857                        &ObjectAttributes,
858                        &Iosb,
859                        0,
860                        FILE_SYNCHRONOUS_IO_ALERT);
861    if (!NT_SUCCESS(Status))
862      {
863         DbgPrint("CSR: Failed to open console. Expect problems.\n");
864      }
865
866    RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\Keyboard");
867    InitializeObjectAttributes(&ObjectAttributes,
868                               &DeviceName,
869                               0,
870                               NULL,
871                               NULL);
872    Status = NtOpenFile(&KeyboardDeviceHandle,
873                        FILE_ALL_ACCESS,
874                        &ObjectAttributes,
875                        &Iosb,
876                        0,
877                        0);
878    if (!NT_SUCCESS(Status))
879      {
880         DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
881      }
882    
883    ActiveConsole = 0;
884    RtlInitializeCriticalSection( &ActiveConsoleLock );
885    Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, &ScrInfo, sizeof( ScrInfo ) );
886    if( !NT_SUCCESS( Status ) )
887      {
888        DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
889        return;
890      }
891    PhysicalConsoleSize = ScrInfo.dwSize;
892 }
893
894 VOID Console_Api( DWORD RefreshEvent )
895 {
896   /* keep reading events from the keyboard and stuffing them into the current
897      console's input queue */
898   ConsoleInput *KeyEventRecord;
899   ConsoleInput *TempInput;
900   IO_STATUS_BLOCK Iosb;
901   NTSTATUS Status;
902   HANDLE Events[2];     // 0 = keyboard, 1 = refresh
903   int c;
904   int updown;
905   PCSRSS_CONSOLE SwapConsole = 0; // console we are thinking about swapping with
906
907   Events[0] = 0;
908   Status = NtCreateEvent( &Events[0], STANDARD_RIGHTS_ALL, NULL, FALSE, FALSE );
909   if( !NT_SUCCESS( Status ) )
910     {
911       DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status );
912       NtTerminateProcess( NtCurrentProcess(), Status );
913     }
914   Events[1] = (HANDLE)RefreshEvent;
915   while( 1 )
916     {
917       KeyEventRecord = RtlAllocateHeap(CsrssApiHeap, 
918                                        0,
919                                        sizeof(ConsoleInput));
920        if ( KeyEventRecord == 0 )
921         {
922           DbgPrint( "CSR: Memory allocation failure!" );
923           continue;
924         }
925       KeyEventRecord->InputEvent.EventType = KEY_EVENT;
926       Status = NtReadFile( KeyboardDeviceHandle, Events[0], NULL, NULL, &Iosb,
927         &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 );
928       if( !NT_SUCCESS( Status ) )
929         {
930           DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
931           RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
932           continue;
933         }
934       if( Status == STATUS_PENDING )
935         {
936           while( 1 )
937             {
938               Status = NtWaitForMultipleObjects( 2, Events, WaitAny, FALSE, NULL );
939               if( Status == STATUS_WAIT_0 + 1 )
940                 {
941                   LOCK;
942                   CsrDrawConsole( ActiveConsole->ActiveBuffer );
943                   UNLOCK;
944                   continue;
945                 }
946               else if( Status != STATUS_WAIT_0 )
947                 {
948                   DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status );
949                   NtTerminateProcess( NtCurrentProcess(), Status );
950                 }
951               else break;
952             }
953         }
954       if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
955         ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED )&&
956           KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_TAB )
957          if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
958             {
959               ANSI_STRING Title;
960               void * Buffer;
961               COORD *pos;
962               
963                /* alt-tab, swap consoles */
964                // move SwapConsole to next console, and print its title
965               LOCK;
966               if( !SwapConsole )
967                 SwapConsole = ActiveConsole;
968               
969               if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED )
970                 SwapConsole = SwapConsole->Prev;
971               else SwapConsole = SwapConsole->Next;
972               Title.MaximumLength = RtlUnicodeStringToAnsiSize( &SwapConsole->Title );
973               Title.Length = 0;
974               Buffer = RtlAllocateHeap( CsrssApiHeap,
975                                         0,
976                                         sizeof( COORD ) + Title.MaximumLength);
977               pos = (COORD *)Buffer;
978               Title.Buffer = Buffer + sizeof( COORD );
979
980               RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Title, FALSE);
981               pos->Y = PhysicalConsoleSize.Y / 2;
982               pos->X = ( PhysicalConsoleSize.X - Title.Length ) / 2;
983               // redraw the console to clear off old title
984               CsrDrawConsole( ActiveConsole->ActiveBuffer );
985               Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
986                                               NULL,
987                                               NULL,
988                                               NULL,
989                                               &Iosb,
990                                               IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
991                                               Buffer,
992                                               sizeof (COORD) + Title.Length,
993                                               NULL,
994                                               0);
995               if( !NT_SUCCESS( Status ) )
996                 {
997                   DPRINT1( "Error writing to console\n" );
998                 }
999               RtlFreeHeap( CsrssApiHeap, 0, Buffer );
1000               
1001               UNLOCK;
1002               RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1003               continue;
1004             }
1005          else {
1006             RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1007             continue;
1008          }
1009       else if( SwapConsole &&
1010                KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_MENU &&
1011                KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == FALSE )
1012         {
1013           // alt key released, swap consoles
1014           PCSRSS_CONSOLE tmp;
1015
1016           LOCK;
1017           if( SwapConsole != ActiveConsole )
1018             {
1019               // first remove swapconsole from the list
1020               SwapConsole->Prev->Next = SwapConsole->Next;
1021               SwapConsole->Next->Prev = SwapConsole->Prev;
1022               // now insert before activeconsole
1023               SwapConsole->Next = ActiveConsole;
1024               SwapConsole->Prev = ActiveConsole->Prev;
1025               ActiveConsole->Prev->Next = SwapConsole;
1026               ActiveConsole->Prev = SwapConsole;
1027             }
1028           ActiveConsole = SwapConsole;
1029           SwapConsole = 0;
1030           CsrDrawConsole( ActiveConsole->ActiveBuffer );
1031
1032           UNLOCK;
1033         }
1034       if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
1035         ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) &&
1036         ( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP ||
1037           KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) )
1038          {
1039             if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
1040                {
1041                   /* scroll up or down */
1042                   LOCK;
1043                   if( ActiveConsole == 0 )
1044                      {
1045                         DbgPrint( "CSR: No Active Console!\n" );
1046                         UNLOCK;
1047                         RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1048                         continue;
1049                      }
1050                   if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP )
1051                      {
1052                         /* only scroll up if there is room to scroll up into */
1053                         if( ActiveConsole->ActiveBuffer->ShowY != ((ActiveConsole->ActiveBuffer->CurrentY + 1) %
1054         ActiveConsole->ActiveBuffer->MaxY) )
1055                            ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY +
1056          ActiveConsole->ActiveBuffer->MaxY - 1) % ActiveConsole->ActiveBuffer->MaxY;
1057                      }
1058                   else if( ActiveConsole->ActiveBuffer->ShowY != ActiveConsole->ActiveBuffer->CurrentY )
1059                      /* only scroll down if there is room to scroll down into */
1060                      if( ActiveConsole->ActiveBuffer->ShowY % ActiveConsole->ActiveBuffer->MaxY != 
1061            ActiveConsole->ActiveBuffer->CurrentY )
1062
1063                         if( ((ActiveConsole->ActiveBuffer->CurrentY + 1) % ActiveConsole->ActiveBuffer->MaxY) != 
1064         (ActiveConsole->ActiveBuffer->ShowY + PhysicalConsoleSize.Y) % ActiveConsole->ActiveBuffer->MaxY )
1065                            ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY + 1) %
1066          ActiveConsole->ActiveBuffer->MaxY;
1067                   CsrDrawConsole( ActiveConsole->ActiveBuffer );
1068                   UNLOCK;
1069                }
1070             RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1071             continue;
1072         }
1073       LOCK;
1074       if( ActiveConsole == 0 )
1075          {
1076             DbgPrint( "CSR: No Active Console!\n" );
1077             UNLOCK;
1078             RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1079             continue;
1080          }
1081       // process special keys if enabled
1082       if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) )
1083           switch( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar )
1084             {
1085             case '\r':
1086               // add a \n to the queue as well
1087               // first add the \r
1088               updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
1089               KeyEventRecord->Echoed = FALSE;
1090               KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
1091         InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1092               ActiveConsole->WaitingChars++;
1093               KeyEventRecord = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( ConsoleInput ) );
1094               if( !KeyEventRecord )
1095                 {
1096                   DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
1097                   UNLOCK;
1098                   continue;
1099                 }
1100               KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1101               KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
1102               KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
1103               KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
1104               KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
1105             }
1106       // add event to the queue
1107       InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1108       // if line input mode is enabled, only wake the client on enter key down
1109       if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT ) ||
1110           ActiveConsole->EarlyReturn ||
1111           ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' &&
1112             KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) )
1113         {
1114           NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1115           if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1116              ActiveConsole->WaitingLines++;
1117         }
1118       KeyEventRecord->Echoed = FALSE;
1119       if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) &&
1120           KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' &&
1121           KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown )
1122          {
1123             // walk the input queue looking for a char to backspace
1124             for( TempInput = (ConsoleInput *)ActiveConsole->InputEvents.Blink;
1125                   TempInput != (ConsoleInput *)&ActiveConsole->InputEvents &&
1126                   (TempInput->InputEvent.EventType != KEY_EVENT ||
1127                   TempInput->InputEvent.Event.KeyEvent.bKeyDown == FALSE ||
1128                   TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' );
1129                   TempInput = (ConsoleInput *)TempInput->ListEntry.Blink );
1130             // if we found one, delete it, otherwise, wake the client
1131             if( TempInput != (ConsoleInput *)&ActiveConsole->InputEvents )
1132                {
1133                   // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
1134       RemoveEntryList(&TempInput->ListEntry);
1135                   if( TempInput->Echoed )
1136                      CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1137                   RtlFreeHeap( CsrssApiHeap, 0, TempInput );
1138       RemoveEntryList(&KeyEventRecord->ListEntry);
1139                   RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1140                   ActiveConsole->WaitingChars -= 2;
1141                }
1142             else NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1143    }
1144       else {
1145          // echo chars if we are supposed to and client is waiting for some
1146          if( ( ActiveConsole->Mode & ENABLE_ECHO_INPUT ) && ActiveConsole->EchoCount &&
1147              KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar &&
1148              KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE &&
1149              KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
1150             {
1151                // mark the char as already echoed
1152                CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1153                ActiveConsole->EchoCount--;
1154                KeyEventRecord->Echoed = TRUE;
1155             }
1156       }
1157       ActiveConsole->WaitingChars++;
1158       if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT) )
1159         NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1160       UNLOCK;
1161     }
1162 }
1163
1164 CSR_API(CsrGetScreenBufferInfo)
1165 {
1166    NTSTATUS Status;
1167    PCSRSS_SCREEN_BUFFER Buff;
1168    PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1169    IO_STATUS_BLOCK Iosb;
1170    
1171    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1172    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1173      sizeof(LPC_MESSAGE);
1174
1175    LOCK;
1176    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle,
1177      (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1178       {
1179          UNLOCK;
1180          return Reply->Status = STATUS_INVALID_HANDLE;
1181       }
1182    pInfo = &Reply->Data.ScreenBufferInfoReply.Info;
1183    if( Buff == ActiveConsole->ActiveBuffer )
1184      {
1185         Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1186     IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, pInfo, sizeof( *pInfo ) );
1187         if( !NT_SUCCESS( Status ) )
1188            DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
1189         Reply->Status = Status;
1190      }
1191    else {
1192       pInfo->dwSize.X = PhysicalConsoleSize.X;
1193       pInfo->dwSize.Y = PhysicalConsoleSize.Y;
1194       pInfo->dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1195       pInfo->dwCursorPosition.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1196       pInfo->wAttributes = Buff->DefaultAttrib;
1197       pInfo->srWindow.Left = 0;
1198       pInfo->srWindow.Right = PhysicalConsoleSize.X - 1;
1199       pInfo->srWindow.Top = 0;
1200       pInfo->srWindow.Bottom = PhysicalConsoleSize.Y - 1;
1201       Reply->Status = STATUS_SUCCESS;
1202    }
1203    UNLOCK;
1204    return Reply->Status;
1205 }
1206
1207 CSR_API(CsrSetCursor)
1208 {
1209    NTSTATUS Status;
1210    PCSRSS_SCREEN_BUFFER Buff;
1211    CONSOLE_SCREEN_BUFFER_INFO Info;
1212    IO_STATUS_BLOCK Iosb;
1213    
1214    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1215    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1216      sizeof(LPC_MESSAGE);
1217
1218    LOCK;
1219    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.SetCursorRequest.ConsoleHandle,
1220      (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1221       {
1222          UNLOCK;
1223          return Reply->Status = STATUS_INVALID_HANDLE;
1224       }
1225    Info.dwCursorPosition = Request->Data.SetCursorRequest.Position;
1226    Info.wAttributes = Buff->DefaultAttrib;
1227    if( Buff == ActiveConsole->ActiveBuffer )
1228       {
1229          Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1230      IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &Info, sizeof( Info ), 0, 0 );
1231         if( !NT_SUCCESS( Status ) )
1232            DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
1233       }
1234
1235    Buff->CurrentX = Info.dwCursorPosition.X + Buff->ShowX;
1236    Buff->CurrentY = (Info.dwCursorPosition.Y + Buff->ShowY) % Buff->MaxY;
1237    UNLOCK;
1238    return Reply->Status = Status;
1239 }
1240
1241 CSR_API(CsrWriteConsoleOutputChar)
1242 {
1243    PBYTE String = Request->Data.WriteConsoleOutputCharRequest.String;
1244    PBYTE Buffer;
1245    PCSRSS_SCREEN_BUFFER Buff;
1246    DWORD X, Y, Length;
1247    NTSTATUS Status;
1248    IO_STATUS_BLOCK Iosb;
1249
1250    DPRINT("CsrWriteConsoleOutputChar\n");
1251    
1252    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1253    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1254      sizeof(LPC_MESSAGE);
1255    LOCK;
1256    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1257       {
1258          UNLOCK;
1259          return Reply->Status = STATUS_INVALID_HANDLE;
1260       }
1261
1262
1263    X = Request->Data.WriteConsoleOutputCharRequest.Coord.X + Buff->ShowX;
1264    Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1265    Length = Request->Data.WriteConsoleOutputCharRequest.Length;
1266    Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1267    while(Length--)
1268    {
1269       *Buffer = *String++;
1270       Buffer += 2;
1271       if (++X == Buff->MaxX)
1272       {
1273          if (++Y == Buff->MaxY)
1274          {
1275             Y = 0;
1276             Buffer = Buff->Buffer;
1277          }
1278          X = 0;
1279       }
1280    }
1281    if( ActiveConsole->ActiveBuffer == Buff )
1282      {
1283        Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1284                                        NULL,
1285                                        NULL,
1286                                        NULL,
1287                                        &Iosb,
1288                                        IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
1289                                        &Request->Data.WriteConsoleOutputCharRequest.Coord,
1290                                        sizeof (COORD) + Request->Data.WriteConsoleOutputCharRequest.Length,
1291                                        NULL,
1292                                        0);
1293        if( !NT_SUCCESS( Status ) )
1294          DPRINT1( "Failed to write output chars: %x\n", Status );
1295      }
1296    Reply->Data.WriteConsoleOutputCharReply.EndCoord.X = X - Buff->ShowX;
1297    Reply->Data.WriteConsoleOutputCharReply.EndCoord.Y = (Y + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1298    UNLOCK;
1299    return Reply->Status = STATUS_SUCCESS;
1300 }
1301
1302 CSR_API(CsrFillOutputChar)
1303 {
1304    PCSRSS_SCREEN_BUFFER Buff;
1305    DWORD X, Y, Length;
1306    BYTE Char;
1307    OUTPUT_CHARACTER Character;
1308    PBYTE Buffer;
1309    NTSTATUS Status;
1310    IO_STATUS_BLOCK Iosb;
1311
1312    DPRINT("CsrFillOutputChar\n");
1313    
1314    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1315    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1316      sizeof(LPC_MESSAGE);
1317
1318    LOCK;
1319    if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1320       {
1321          UNLOCK;
1322          return Reply->Status = STATUS_INVALID_HANDLE;
1323       }
1324    X = Request->Data.FillOutputRequest.Position.X + Buff->ShowX;
1325    Y = (Request->Data.FillOutputRequest.Position.Y + Buff->ShowY) % Buff->MaxY;
1326    Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1327    Char = Request->Data.FillOutputRequest.Char;
1328    Length = Request->Data.FillOutputRequest.Length;
1329    while (Length--)
1330    {
1331       *Buffer = Char;
1332       Buffer += 2;
1333       if( ++X == Buff->MaxX )
1334       {
1335          if( ++Y == Buff->MaxY )
1336          {
1337             Y = 0;
1338             Buffer = Buff->Buffer;
1339          }
1340          X = 0;
1341       }
1342    }
1343    if( Buff == ActiveConsole->ActiveBuffer )
1344    {
1345       Character.dwCoord = Request->Data.FillOutputRequest.Position;
1346       Character.cCharacter = Char;
1347       Character.nLength = Request->Data.FillOutputRequest.Length;
1348       Status = NtDeviceIoControlFile( ConsoleDeviceHandle, 
1349                                       NULL, 
1350                                       NULL, 
1351                                       NULL, 
1352                                       &Iosb,
1353                                       IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER,
1354                                       &Character,
1355                                       sizeof(Character),
1356                                       NULL,
1357                                       0);
1358       if (!NT_SUCCESS(Status))
1359           DPRINT1( "Failed to write output characters to console\n" );
1360    }
1361    UNLOCK;
1362    return Reply->Status;
1363 }
1364
1365 CSR_API(CsrReadInputEvent)
1366 {
1367    PLIST_ENTRY CurrentEntry;
1368    PCSRSS_CONSOLE Console;
1369    NTSTATUS Status;
1370    ConsoleInput *Input;
1371    
1372    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1373    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1374       sizeof(LPC_MESSAGE);
1375    Reply->Data.ReadInputReply.Event = ProcessData->ConsoleEvent;
1376    
1377    LOCK;
1378    Status = CsrGetObject( ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, (Object_t **)&Console );
1379    if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? 0 : STATUS_INVALID_HANDLE))
1380       {
1381          Reply->Status = Status;
1382          UNLOCK;
1383          return Status;
1384       }
1385
1386    // only get input if there is any
1387    if( Console->InputEvents.Flink != &Console->InputEvents )
1388      {
1389        CurrentEntry = RemoveHeadList(&Console->InputEvents);
1390        Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1391        Reply->Data.ReadInputReply.Input = Input->InputEvent;
1392
1393        if( Input->InputEvent.EventType == KEY_EVENT )
1394          {
1395            if( Console->Mode & ENABLE_LINE_INPUT &&
1396                Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE &&
1397                Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1398              Console->WaitingLines--;
1399            Console->WaitingChars--;
1400          }
1401        RtlFreeHeap( CsrssApiHeap, 0, Input );
1402
1403        if (Console->InputEvents.Flink != &Console->InputEvents &&
1404            Reply->Data.ReadInputReply.Input.EventType == KEY_EVENT &&
1405            Reply->Data.ReadInputReply.Input.Event.KeyEvent.uChar.AsciiChar == '\r')
1406        {
1407           Input = CONTAINING_RECORD(Console->InputEvents.Flink, ConsoleInput, ListEntry);
1408           if (Input->InputEvent.EventType == KEY_EVENT &&
1409               Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' && 
1410               ((Input->InputEvent.Event.KeyEvent.bKeyDown && Reply->Data.ReadInputReply.Input.Event.KeyEvent.bKeyDown) ||
1411               (Input->InputEvent.Event.KeyEvent.bKeyDown==FALSE && Reply->Data.ReadInputReply.Input.Event.KeyEvent.bKeyDown==FALSE)))
1412           {
1413             if(Console->Mode & ENABLE_LINE_INPUT &&
1414                Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE &&
1415                Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1416              Console->WaitingLines--;
1417             Console->WaitingChars--;
1418             RemoveHeadList(&Console->InputEvents);
1419             RtlFreeHeap( CsrssApiHeap, 0, Input );
1420           }
1421        }
1422
1423        Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents) ? TRUE : FALSE;
1424        Status = STATUS_SUCCESS;
1425        Console->EarlyReturn = FALSE; // clear early return
1426      }
1427    else {
1428       Status = STATUS_PENDING;
1429       Console->EarlyReturn = TRUE;  // mark for early return
1430    }
1431    UNLOCK;
1432    return Reply->Status = Status;
1433 }
1434
1435 CSR_API(CsrWriteConsoleOutputAttrib)
1436 {
1437    PCSRSS_SCREEN_BUFFER Buff;
1438    PUCHAR Buffer, Attribute;
1439    NTSTATUS Status;
1440    int X, Y, Length;
1441    IO_STATUS_BLOCK Iosb;
1442
1443    DPRINT("CsrWriteConsoleOutputAttrib\n");
1444    
1445    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1446    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1447       sizeof(LPC_MESSAGE);
1448    LOCK;
1449    Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1450    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1451       {
1452          Reply->Status = Status;
1453          UNLOCK;
1454          return Status;
1455       }
1456    X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X + Buff->ShowX;
1457    Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1458    Length = Request->Data.WriteConsoleOutputAttribRequest.Length;
1459    Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
1460    Attribute = Request->Data.WriteConsoleOutputAttribRequest.String;
1461    while (Length--)
1462    {
1463       *Buffer = *Attribute++;
1464       Buffer += 2;
1465       if( ++X == Buff->MaxX )
1466       {
1467          X = 0;
1468          if( ++Y == Buff->MaxY )
1469          {
1470             Y = 0;
1471             Buffer = Buff->Buffer + 1;
1472          }
1473       }
1474    }
1475    if( Buff == ActiveConsole->ActiveBuffer )
1476       {
1477         Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1478                                         NULL,
1479                                         NULL,
1480                                         NULL,
1481                                         &Iosb,
1482                                         IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE,
1483                                         &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1484                                         Request->Data.WriteConsoleOutputAttribRequest.Length +
1485                                         sizeof (COORD),
1486                                         NULL,
1487                                         0 );
1488         if( !NT_SUCCESS( Status ) )
1489           DPRINT1( "Failed to write output attributes to console\n" );
1490       }
1491    Reply->Data.WriteConsoleOutputAttribReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1492    Reply->Data.WriteConsoleOutputAttribReply.EndCoord.Y = ( Buff->CurrentY + Buff->MaxY - Buff->ShowY ) % Buff->MaxY;
1493    UNLOCK;
1494    return Reply->Status = STATUS_SUCCESS;
1495 }
1496
1497 CSR_API(CsrFillOutputAttrib)
1498 {
1499    OUTPUT_ATTRIBUTE Attribute;
1500    PCSRSS_SCREEN_BUFFER Buff;
1501    PCHAR Buffer;
1502    NTSTATUS Status;
1503    int X, Y, Length;
1504    IO_STATUS_BLOCK Iosb;
1505    UCHAR Attr;
1506
1507    DPRINT("CsrFillOutputAttrib\n");
1508    
1509    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1510    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1511       sizeof(LPC_MESSAGE);
1512    LOCK;
1513    Status = CsrGetObject( ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1514    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1515       {
1516          Reply->Status = Status;
1517          UNLOCK;
1518          return Status;
1519       }
1520    X = Request->Data.FillOutputAttribRequest.Coord.X + Buff->ShowX;
1521    Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1522    Length = Request->Data.FillOutputAttribRequest.Length;
1523    Attr = Request->Data.FillOutputAttribRequest.Attribute;
1524    Buffer = &Buff->Buffer[(Y * Buff->MaxX * 2) + (X * 2) + 1];
1525    while(Length--)
1526    {
1527       *Buffer = Attr;
1528       Buffer += 2;
1529       if( ++X == Buff->MaxX )
1530       {
1531          X = 0;
1532          if( ++Y == Buff->MaxY )
1533          {
1534             Y = 0;
1535             Buffer = Buff->Buffer + 1;
1536          }
1537       }
1538    }
1539    if( Buff == ActiveConsole->ActiveBuffer )
1540    {
1541       Attribute.wAttribute = Attr;
1542       Attribute.nLength = Request->Data.FillOutputAttribRequest.Length;
1543       Attribute.dwCoord = Request->Data.FillOutputAttribRequest.Coord;
1544       Status = NtDeviceIoControlFile( ConsoleDeviceHandle, 
1545                                       NULL, 
1546                                       NULL, 
1547                                       NULL, 
1548                                       &Iosb,
1549                                       IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE, 
1550                                       &Attribute,
1551                                       sizeof(OUTPUT_ATTRIBUTE), 
1552                                       NULL, 
1553                                       0);
1554       if( !NT_SUCCESS( Status ) )
1555          DPRINT1( "Failed to fill output attributes to console\n" );
1556    }
1557    UNLOCK;
1558    return Reply->Status = STATUS_SUCCESS;
1559 }
1560
1561
1562 CSR_API(CsrGetCursorInfo)
1563 {
1564    PCSRSS_SCREEN_BUFFER Buff;
1565    NTSTATUS Status;
1566    
1567    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1568    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1569       sizeof(LPC_MESSAGE);
1570    LOCK;
1571    Status = CsrGetObject( ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1572    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1573       {
1574          Reply->Status = Status;
1575          UNLOCK;
1576          return Status;
1577       }
1578    Reply->Data.GetCursorInfoReply.Info = Buff->CursorInfo;
1579    UNLOCK;
1580    return Reply->Status = STATUS_SUCCESS;
1581 }
1582
1583 CSR_API(CsrSetCursorInfo)
1584 {
1585    PCSRSS_SCREEN_BUFFER Buff;
1586    NTSTATUS Status;
1587    IO_STATUS_BLOCK Iosb;
1588    
1589    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1590    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1591       sizeof(LPC_MESSAGE);
1592    LOCK;
1593    Status = CsrGetObject( ProcessData,
1594      Request->Data.SetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1595
1596    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1597       {
1598          Reply->Status = Status;
1599          UNLOCK;
1600          return Status;
1601       }
1602    Buff->CursorInfo = Request->Data.SetCursorInfoRequest.Info;
1603    if( Buff == ActiveConsole->ActiveBuffer )
1604       {
1605          Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_CURSOR_INFO, &Buff->CursorInfo, sizeof( Buff->CursorInfo ), 0, 0 );
1606          if( !NT_SUCCESS( Status ) )
1607             {
1608                DbgPrint( "CSR: Failed to set cursor info\n" );
1609                return Reply->Status = Status;
1610             }
1611       }
1612    UNLOCK;
1613    return Reply->Status = STATUS_SUCCESS;
1614 }
1615
1616 CSR_API(CsrSetTextAttrib)
1617 {
1618    NTSTATUS Status;
1619    CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
1620    IO_STATUS_BLOCK Iosb;
1621    PCSRSS_SCREEN_BUFFER Buff;
1622
1623    DPRINT("CsrSetTextAttrib\n");
1624    
1625    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1626    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1627       sizeof(LPC_MESSAGE);
1628    LOCK;
1629    Status = CsrGetObject( ProcessData, Request->Data.SetAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1630    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1631       {
1632          Reply->Status = Status;
1633          UNLOCK;
1634          return Status;
1635       }
1636    Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1637    if( Buff == ActiveConsole->ActiveBuffer )
1638       {
1639          ScrInfo.wAttributes = Buff->DefaultAttrib;
1640          ScrInfo.dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;   
1641          ScrInfo.dwCursorPosition.Y = ((Buff->CurrentY + Buff->MaxY) - Buff->ShowY) % Buff->MaxY;
1642          Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
1643          if( !NT_SUCCESS( Status ) )
1644             {
1645                DbgPrint( "CSR: Failed to set console info\n" );
1646                UNLOCK;
1647                return Reply->Status = Status;
1648             }
1649       }
1650    UNLOCK;
1651    return Reply->Status = STATUS_SUCCESS;
1652 }
1653
1654 CSR_API(CsrSetConsoleMode)
1655 {
1656    NTSTATUS Status;
1657    PCSRSS_CONSOLE Console;
1658    PCSRSS_SCREEN_BUFFER Buff;
1659
1660    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1661    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1662    LOCK;
1663    Status = CsrGetObject( ProcessData,
1664      Request->Data.SetConsoleModeRequest.ConsoleHandle,
1665      (Object_t **)&Console );
1666    if( !NT_SUCCESS( Status ) )
1667       {
1668          Reply->Status = Status;
1669          UNLOCK;
1670          return Status;
1671       }
1672
1673    Buff = (PCSRSS_SCREEN_BUFFER)Console;
1674    if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1675       Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1676    else if( Console->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1677       Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1678    else {
1679       Reply->Status = STATUS_INVALID_HANDLE;
1680       UNLOCK;
1681       return Status;
1682    }
1683    UNLOCK;
1684    Reply->Status = STATUS_SUCCESS;
1685    return Reply->Status;
1686 }
1687
1688 CSR_API(CsrGetConsoleMode)
1689 {
1690    NTSTATUS Status;
1691    PCSRSS_CONSOLE Console;
1692    PCSRSS_SCREEN_BUFFER Buff;   /* gee, I really wish I could use an anonymous union here */
1693
1694    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1695    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1696    LOCK;
1697    Status = CsrGetObject( ProcessData,
1698      Request->Data.GetConsoleModeRequest.ConsoleHandle,
1699      (Object_t **)&Console );
1700    if( !NT_SUCCESS( Status ) )
1701       {
1702          Reply->Status = Status;
1703          UNLOCK;
1704          return Status;
1705       }
1706    Reply->Status = STATUS_SUCCESS;
1707    Buff = (PCSRSS_SCREEN_BUFFER)Console;
1708    if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1709       Reply->Data.GetConsoleModeReply.ConsoleMode = Console->Mode;
1710    else if( Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1711       Reply->Data.GetConsoleModeReply.ConsoleMode = Buff->Mode;
1712    else Status = STATUS_INVALID_HANDLE;
1713    UNLOCK;
1714    return Reply->Status;
1715 }
1716
1717 CSR_API(CsrCreateScreenBuffer)
1718 {
1719    PCSRSS_SCREEN_BUFFER Buff;
1720    NTSTATUS Status;
1721    
1722    Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1723    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1724
1725    if (ProcessData == NULL)
1726    {
1727      return(Reply->Status = STATUS_INVALID_PARAMETER);
1728    }
1729
1730    Buff = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
1731    if( !Buff )
1732       Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
1733    LOCK;
1734    Status = CsrInitConsoleScreenBuffer( Buff );
1735    if( !NT_SUCCESS( Status ) )
1736       Reply->Status = Status;
1737    else {
1738       Status = CsrInsertObject( ProcessData, &Reply->Data.CreateScreenBufferReply.OutputHandle, &Buff->Header );
1739       if( !NT_SUCCESS( Status ) )
1740          Reply->Status = Status;
1741       else Reply->Status = STATUS_SUCCESS;
1742    }
1743    UNLOCK;
1744    return Reply->Status;
1745 }
1746
1747 CSR_API(CsrSetScreenBuffer)
1748 {
1749    NTSTATUS Status;
1750    PCSRSS_SCREEN_BUFFER Buff;
1751    
1752    Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1753    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1754    LOCK;
1755    Status = CsrGetObject( ProcessData, Request->Data.SetActiveScreenBufferRequest.OutputHandle, (Object_t **)&Buff );
1756    if( !NT_SUCCESS( Status ) )
1757       Reply->Status = Status;
1758    else {
1759       // drop reference to old buffer, maybe delete
1760       if( !InterlockedDecrement( &ProcessData->Console->ActiveBuffer->Header.ReferenceCount ) )
1761          CsrDeleteScreenBuffer( ProcessData->Console->ActiveBuffer );
1762       // tie console to new buffer
1763       ProcessData->Console->ActiveBuffer = Buff;
1764       // inc ref count on new buffer
1765       InterlockedIncrement( &Buff->Header.ReferenceCount );
1766       // if the console is active, redraw it
1767       if( ActiveConsole == ProcessData->Console )
1768          CsrDrawConsole( Buff );
1769       Reply->Status = STATUS_SUCCESS;
1770    }
1771    UNLOCK;
1772    return Reply->Status;
1773 }
1774
1775 CSR_API(CsrSetTitle)
1776 {
1777   NTSTATUS Status;
1778   PCSRSS_CONSOLE Console;
1779   
1780   Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1781   Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1782   LOCK;
1783   Status = CsrGetObject( ProcessData, Request->Data.SetTitleRequest.Console, (Object_t **)&Console );
1784   if( !NT_SUCCESS( Status ) )
1785     Reply->Status = Status;  
1786   else {
1787     // copy title to console
1788     RtlFreeUnicodeString( &Console->Title );
1789     RtlCreateUnicodeString( &Console->Title, Request->Data.SetTitleRequest.Title );
1790     Reply->Status = STATUS_SUCCESS;
1791   }
1792   UNLOCK;
1793   return Reply->Status;
1794 }
1795
1796 CSR_API(CsrGetTitle)
1797 {
1798         NTSTATUS        Status;
1799         PCSRSS_CONSOLE  Console;
1800   
1801         Reply->Header.MessageSize = sizeof (CSRSS_API_REPLY);
1802         Reply->Header.DataSize =
1803                 sizeof (CSRSS_API_REPLY)
1804                 - sizeof(LPC_MESSAGE);
1805         LOCK;
1806         Status = CsrGetObject (
1807                         ProcessData,
1808                         Request->Data.GetTitleRequest.ConsoleHandle,
1809                         (Object_t **) & Console
1810                         );
1811    if ( !NT_SUCCESS( Status ) )
1812    {
1813       Reply->Status = Status;
1814    }
1815         else
1816         {
1817                 HANDLE ConsoleHandle = Request->Data.GetTitleRequest.ConsoleHandle;
1818                 
1819                 /* Copy title of the console to the user title buffer */
1820                 RtlZeroMemory (
1821                         & Reply->Data.GetTitleReply,
1822                         sizeof (CSRSS_GET_TITLE_REPLY)
1823                         );
1824                 Reply->Data.GetTitleReply.ConsoleHandle = ConsoleHandle;
1825                 Reply->Data.GetTitleReply.Length = Console->Title.Length;
1826                 wcscpy (Reply->Data.GetTitleReply.Title, Console->Title.Buffer);
1827                 Reply->Header.MessageSize += Console->Title.Length;
1828                 Reply->Header.DataSize += Console->Title.Length;
1829                 Reply->Status = STATUS_SUCCESS;
1830         }
1831         UNLOCK;
1832         return Reply->Status;
1833 }
1834
1835 CSR_API(CsrWriteConsoleOutput)
1836 {
1837    SHORT i, X, Y, SizeX, SizeY;
1838    PCSRSS_SCREEN_BUFFER Buff;
1839    SMALL_RECT ScreenBuffer;
1840    CHAR_INFO* CurCharInfo;
1841    SMALL_RECT WriteRegion;
1842    CHAR_INFO* CharInfo;
1843    COORD BufferCoord;
1844    COORD BufferSize;
1845    NTSTATUS Status;
1846    DWORD Offset;
1847    DWORD PSize;
1848
1849    DPRINT("CsrWriteConsoleOutput\n");
1850
1851    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1852    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1853    LOCK;
1854    Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputRequest.ConsoleHandle, (Object_t **)&Buff );
1855    if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1856       {
1857          Reply->Status = Status;
1858          UNLOCK;
1859          return Status;
1860       }
1861
1862    BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
1863    PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
1864    BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
1865    CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
1866    if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
1867        (((PVOID)CharInfo + PSize) > 
1868         (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
1869      {
1870        UNLOCK;
1871        Reply->Status = STATUS_ACCESS_VIOLATION;
1872        return(Reply->Status);
1873      }
1874    WriteRegion = Request->Data.WriteConsoleOutputRequest.WriteRegion;
1875
1876    SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(WriteRegion));
1877    SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(WriteRegion));
1878    WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
1879    WriteRegion.Right = WriteRegion.Left + SizeX - 1;
1880
1881    /* Make sure WriteRegion is inside the screen buffer */
1882    CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1883    if (!CsrpGetIntersection(&WriteRegion, ScreenBuffer, WriteRegion))
1884       {
1885          UNLOCK;
1886          /* It is okay to have a WriteRegion completely outside the screen buffer.
1887             No data is written then. */
1888          return (Reply->Status = STATUS_SUCCESS);
1889       }
1890
1891    for ( i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++ )
1892    {
1893      CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
1894      Offset = (((Y + Buff->ShowY) % Buff->MaxY) * Buff->MaxX + WriteRegion.Left) * 2;
1895      for ( X = WriteRegion.Left; X <= WriteRegion.Right; X++ )
1896       {
1897         SET_CELL_BUFFER(Buff, Offset, CurCharInfo->Char.AsciiChar, CurCharInfo->Attributes);
1898         CurCharInfo++;
1899       }
1900    }
1901
1902    if( Buff == ActiveConsole->ActiveBuffer )
1903      {
1904         CsrpDrawRegion( ActiveConsole->ActiveBuffer, WriteRegion );
1905      }
1906
1907    UNLOCK;
1908    Reply->Data.WriteConsoleOutputReply.WriteRegion.Right = WriteRegion.Left + SizeX - 1;
1909    Reply->Data.WriteConsoleOutputReply.WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
1910    Reply->Data.WriteConsoleOutputReply.WriteRegion.Left = WriteRegion.Left;
1911    Reply->Data.WriteConsoleOutputReply.WriteRegion.Top = WriteRegion.Top;
1912    return (Reply->Status = STATUS_SUCCESS);
1913 }
1914
1915 CSR_API(CsrFlushInputBuffer)
1916 {
1917   PLIST_ENTRY CurrentEntry;
1918   PLIST_ENTRY NextEntry;
1919   PCSRSS_CONSOLE Console;
1920   ConsoleInput* Input;
1921   NTSTATUS Status;
1922
1923   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1924   Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1925   LOCK;
1926   Status = CsrGetObject( ProcessData, Request->Data.FlushInputBufferRequest.ConsoleInput, (Object_t **)&Console );
1927   if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1928     {
1929         Reply->Status = Status;
1930         UNLOCK;
1931         return Status;
1932     }
1933
1934   /* Discard all entries in the input event queue */
1935   while (!IsListEmpty(&Console->InputEvents))
1936     {
1937       CurrentEntry = RemoveHeadList(&Console->InputEvents);
1938       Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1939       /* Destroy the event */
1940       RtlFreeHeap( CsrssApiHeap, 0, Input );
1941     }
1942   Console->WaitingChars=0;
1943   UNLOCK;
1944
1945   return (Reply->Status = STATUS_SUCCESS);
1946 }
1947
1948 CSR_API(CsrScrollConsoleScreenBuffer)
1949 {
1950   SHORT i, X, Y, SizeX, SizeY;
1951   PCSRSS_SCREEN_BUFFER Buff;
1952   SMALL_RECT ScreenBuffer;
1953   SMALL_RECT SrcRegion;
1954   SMALL_RECT DstRegion;
1955   SMALL_RECT FillRegion;
1956   IO_STATUS_BLOCK Iosb;
1957   CHAR_INFO* CharInfo;
1958   NTSTATUS Status;
1959   DWORD SrcOffset;
1960   DWORD DstOffset;
1961   BOOLEAN DoFill;
1962
1963   ALIAS(ConsoleHandle,Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle);
1964   ALIAS(ScrollRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle);
1965   ALIAS(UseClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle);
1966   ALIAS(ClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle);
1967   ALIAS(DestinationOrigin,Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin);
1968   ALIAS(Fill,Request->Data.ScrollConsoleScreenBufferRequest.Fill);
1969
1970   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1971   Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1972   LOCK;
1973   Status = CsrGetObject( ProcessData, ConsoleHandle, (Object_t **)&Buff );
1974   if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1975   {
1976     Reply->Status = Status;
1977     UNLOCK;
1978     return Status;
1979   }
1980
1981   /* Make sure source rectangle is inside the screen buffer */
1982   CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1983   if (!CsrpGetIntersection(&SrcRegion, ScreenBuffer, ScrollRectangle))
1984     {
1985       UNLOCK;
1986       return (Reply->Status = STATUS_INVALID_PARAMETER);
1987     }
1988
1989   if (UseClipRectangle)
1990     {
1991       if (!CsrpGetIntersection(&SrcRegion, SrcRegion, ClipRectangle))
1992         {
1993           UNLOCK;
1994           return (Reply->Status = STATUS_SUCCESS);
1995         }
1996     }
1997
1998
1999   CsrpInitRect(
2000     DstRegion,
2001     DestinationOrigin.Y,
2002     DestinationOrigin.X,
2003     DestinationOrigin.Y + CsrpRectHeight(ScrollRectangle) - 1,
2004     DestinationOrigin.X + CsrpRectWidth(ScrollRectangle) - 1)
2005
2006   /* Make sure destination rectangle is inside the screen buffer */
2007   if (!CsrpGetIntersection(&DstRegion, DstRegion, ScreenBuffer))
2008     {
2009       UNLOCK;
2010       return (Reply->Status = STATUS_INVALID_PARAMETER);
2011     }
2012
2013   CsrpCopyRegion(Buff, SrcRegion, DstRegion);
2014
2015
2016   /* Get the region that should be filled with the specified character and attributes */
2017
2018   DoFill = FALSE;
2019
2020   CsrpGetUnion(&FillRegion, SrcRegion, DstRegion);
2021
2022   if (CsrpSubtractRect(&FillRegion, FillRegion, DstRegion))
2023     {
2024       /* FIXME: The subtracted rectangle is off by one line */
2025       FillRegion.Top += 1;
2026
2027       CsrpFillRegion(Buff, FillRegion, Fill);
2028       DoFill = TRUE;
2029     }
2030
2031   if (Buff == ActiveConsole->ActiveBuffer)
2032     {
2033       /* Draw destination region */
2034       CsrpDrawRegion(ActiveConsole->ActiveBuffer, DstRegion);
2035
2036       if (DoFill)
2037         {
2038           /* Draw filled region */
2039           CsrpDrawRegion(ActiveConsole->ActiveBuffer, FillRegion);
2040         }
2041     }
2042
2043   UNLOCK;
2044   return(Reply->Status = STATUS_SUCCESS);
2045 }
2046
2047
2048 CSR_API(CsrReadConsoleOutputChar)
2049 {
2050   NTSTATUS Status;
2051   PCSRSS_SCREEN_BUFFER ScreenBuffer;
2052   DWORD Xpos, Ypos;
2053   BYTE* ReadBuffer;
2054   DWORD i;
2055
2056   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2057   Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2058   ReadBuffer = Reply->Data.ReadConsoleOutputCharReply.String;
2059
2060   LOCK;
2061
2062   Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2063   if (!NT_SUCCESS(Status))
2064     {
2065       Reply->Status = Status;
2066       UNLOCK;
2067       return(Reply->Status);
2068     }
2069
2070   if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2071     {
2072       Reply->Status = STATUS_INVALID_HANDLE;
2073       UNLOCK;
2074       return(Reply->Status);
2075     }
2076
2077   Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X + ScreenBuffer->ShowX;
2078   Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
2079
2080   for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
2081     {
2082       *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX)];
2083
2084       ReadBuffer++;
2085       Xpos++;
2086
2087       if (Xpos == ScreenBuffer->MaxX)
2088         {
2089           Xpos = 0;
2090           Ypos++;
2091
2092           if (Ypos == ScreenBuffer->MaxY)
2093             Ypos = 0;
2094         }
2095     }
2096
2097   *ReadBuffer = 0;
2098
2099   Reply->Status = STATUS_SUCCESS;
2100   Reply->Data.ReadConsoleOutputCharReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
2101   Reply->Data.ReadConsoleOutputCharReply.EndCoord.Y = (Ypos - ScreenBuffer->ShowY + ScreenBuffer->MaxY) % ScreenBuffer->MaxY;
2102   Reply->Header.MessageSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2103   Reply->Header.DataSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2104
2105   UNLOCK;
2106
2107   return(Reply->Status);
2108 }
2109
2110
2111 CSR_API(CsrReadConsoleOutputAttrib)
2112 {
2113   NTSTATUS Status;
2114   PCSRSS_SCREEN_BUFFER ScreenBuffer;
2115   DWORD Xpos, Ypos;
2116   CHAR* ReadBuffer;
2117   DWORD i;
2118
2119   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2120   Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2121   ReadBuffer = Reply->Data.ReadConsoleOutputAttribReply.String;
2122
2123   LOCK;
2124
2125   Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2126   if (!NT_SUCCESS(Status))
2127     {
2128       Reply->Status = Status;
2129       UNLOCK;
2130       return(Reply->Status);
2131     }
2132
2133   if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2134     {
2135       Reply->Status = STATUS_INVALID_HANDLE;
2136       UNLOCK;
2137       return(Reply->Status);
2138     }
2139
2140   Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X + ScreenBuffer->ShowX;
2141   Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
2142
2143   for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2144     {
2145       *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX) + 1];
2146
2147       ReadBuffer++;
2148       Xpos++;
2149
2150       if (Xpos == ScreenBuffer->MaxX)
2151         {
2152           Xpos = 0;
2153           Ypos++;
2154
2155           if (Ypos == ScreenBuffer->MaxY)
2156             Ypos = 0;
2157         }
2158     }
2159
2160   *ReadBuffer = 0;
2161
2162   Reply->Status = STATUS_SUCCESS;
2163   Reply->Data.ReadConsoleOutputAttribReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
2164   Reply->Data.ReadConsoleOutputAttribReply.EndCoord.Y = (Ypos - ScreenBuffer->ShowY + ScreenBuffer->MaxY) % ScreenBuffer->MaxY;
2165   Reply->Header.MessageSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2166   Reply->Header.DataSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2167
2168   UNLOCK;
2169
2170   return(Reply->Status);
2171 }
2172
2173
2174 CSR_API(CsrGetNumberOfConsoleInputEvents)
2175 {
2176   NTSTATUS Status;
2177   PCSRSS_CONSOLE Console;
2178   PLIST_ENTRY CurrentItem;
2179   DWORD NumEvents;
2180   
2181   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2182   Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2183
2184   LOCK;
2185
2186   Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2187   if (!NT_SUCCESS(Status))
2188     {
2189       Reply->Status = Status;
2190       UNLOCK;
2191       return(Reply->Status);
2192     }
2193
2194   if (Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2195     {
2196       Reply->Status = STATUS_INVALID_HANDLE;
2197       UNLOCK;
2198       return(Reply->Status);
2199     }
2200   
2201   CurrentItem = &Console->InputEvents;
2202   NumEvents = 0;
2203   
2204   // If there are any events ...
2205   if(CurrentItem->Flink != CurrentItem)
2206   {
2207     do
2208     {
2209       CurrentItem = CurrentItem->Flink;
2210       ++NumEvents;
2211     }while(CurrentItem != &Console->InputEvents);
2212   }
2213   
2214   UNLOCK;
2215   
2216   Reply->Status = STATUS_SUCCESS;
2217   Reply->Data.GetNumInputEventsReply.NumInputEvents = NumEvents;
2218    
2219   return Reply->Status;
2220 }
2221
2222
2223 CSR_API(CsrPeekConsoleInput)
2224 {
2225    NTSTATUS Status;
2226    PCSRSS_CONSOLE Console;
2227    DWORD Size;
2228    DWORD Length;
2229    PLIST_ENTRY CurrentItem;
2230    PLIST_ENTRY NextItem;
2231    PINPUT_RECORD InputRecord;
2232    ConsoleInput* Item;
2233    UINT NumItems;
2234    
2235    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2236    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2237    
2238    LOCK;
2239    
2240    Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2241    if(!NT_SUCCESS(Status))
2242    {
2243       Reply->Status = Status;
2244       UNLOCK;
2245       return Reply->Status;
2246    }
2247
2248    if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2249    {
2250       Reply->Status = STATUS_INVALID_HANDLE;
2251       UNLOCK;
2252       return Reply->Status;
2253    }
2254    
2255    InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2256    Length = Request->Data.PeekConsoleInputRequest.Length;
2257    Size = Length * sizeof(INPUT_RECORD);
2258    
2259     if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2260          || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2261    {
2262       UNLOCK;
2263       Reply->Status = STATUS_ACCESS_VIOLATION;
2264       return Reply->Status ;
2265    }
2266    
2267    NumItems = 0;
2268    
2269    if(!IsListEmpty(&Console->InputEvents))
2270    {
2271       CurrentItem = &Console->InputEvents;
2272    
2273       while(NumItems < Length)
2274       {
2275          ++NumItems;
2276          Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2277          *InputRecord++ = Item->InputEvent;
2278          
2279          if(CurrentItem->Flink == &Console->InputEvents)
2280             break;
2281          else
2282             CurrentItem = CurrentItem->Flink;
2283       }
2284    }
2285
2286    UNLOCK;
2287    
2288    Reply->Status = STATUS_SUCCESS;
2289    Reply->Data.PeekConsoleInputReply.Length = NumItems;
2290    return Reply->Status;
2291 }
2292
2293
2294 CSR_API(CsrReadConsoleOutput)
2295 {
2296    PCHAR_INFO CharInfo;
2297    PCHAR_INFO CurCharInfo;
2298    PCSRSS_SCREEN_BUFFER ScreenBuffer;
2299    DWORD Size;
2300    DWORD Length;
2301    DWORD SizeX, SizeY;
2302    NTSTATUS Status;
2303    COORD BufferSize;
2304    COORD BufferCoord;
2305    SMALL_RECT ReadRegion;
2306    SMALL_RECT ScreenRect;
2307    DWORD i, Y, X, Offset;
2308       
2309    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2310    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2311   
2312    LOCK;
2313   
2314    Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2315    if(!NT_SUCCESS(Status))
2316    {
2317       Reply->Status = Status;
2318       UNLOCK;
2319       return Reply->Status;
2320    }
2321
2322    if(ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2323    {
2324       Reply->Status = STATUS_INVALID_HANDLE;
2325       UNLOCK;
2326       return Reply->Status;
2327    }
2328    
2329    CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
2330    ReadRegion = Request->Data.ReadConsoleOutputRequest.ReadRegion;
2331    BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
2332    BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
2333    Length = BufferSize.X * BufferSize.Y;
2334    Size = Length * sizeof(INPUT_RECORD);
2335    
2336     if(((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
2337          || (((PVOID)CharInfo + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2338    {
2339       UNLOCK;
2340       Reply->Status = STATUS_ACCESS_VIOLATION;
2341       return Reply->Status ;
2342    }
2343    
2344    SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(ReadRegion));
2345    SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(ReadRegion));
2346    ReadRegion.Bottom = ReadRegion.Top + SizeY;
2347    ReadRegion.Right = ReadRegion.Left + SizeX;
2348
2349    CsrpInitRect(ScreenRect, 0, 0, ScreenBuffer->MaxY - 1, ScreenBuffer->MaxX - 1);
2350    if (!CsrpGetIntersection(&ReadRegion, ScreenRect, ReadRegion))
2351    {
2352       UNLOCK;
2353       Reply->Status = STATUS_SUCCESS;
2354       return Reply->Status;
2355    }
2356    
2357    for(i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
2358    {
2359      CurCharInfo = CharInfo + (i * BufferSize.Y);
2360      
2361      Offset = (((Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY) * ScreenBuffer->MaxX + ReadRegion.Left) * 2;
2362      for(X = ReadRegion.Left; X < ReadRegion.Right; ++X)
2363      {
2364         CurCharInfo->Char.AsciiChar = GET_CELL_BUFFER(ScreenBuffer, Offset);
2365         CurCharInfo->Attributes = GET_CELL_BUFFER(ScreenBuffer, Offset);
2366         ++CurCharInfo;
2367      }
2368   }
2369   
2370    UNLOCK;
2371    
2372    Reply->Status = STATUS_SUCCESS;
2373    Reply->Data.ReadConsoleOutputReply.ReadRegion.Right = ReadRegion.Left + SizeX - 1;
2374    Reply->Data.ReadConsoleOutputReply.ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
2375    Reply->Data.ReadConsoleOutputReply.ReadRegion.Left = ReadRegion.Left;
2376    Reply->Data.ReadConsoleOutputReply.ReadRegion.Top = ReadRegion.Top;
2377    
2378    return Reply->Status;
2379 }
2380
2381
2382 CSR_API(CsrWriteConsoleInput)
2383 {
2384    PINPUT_RECORD InputRecord;
2385    PCSRSS_CONSOLE Console;
2386    NTSTATUS Status;
2387    DWORD Length;
2388    DWORD Size;
2389    DWORD i;
2390    PLIST_ENTRY NextItem;
2391    ConsoleInput* Record;
2392    
2393    Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2394    Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2395    
2396    LOCK;
2397    
2398    Status = CsrGetObject(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, (Object_t**)&Console);
2399    if(!NT_SUCCESS(Status))
2400    {
2401       Reply->Status = Status;
2402       UNLOCK;
2403       return Reply->Status;
2404    }
2405
2406    if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2407    {
2408       Reply->Status = STATUS_INVALID_HANDLE;
2409       UNLOCK;
2410       return Reply->Status;
2411    }
2412    
2413    InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
2414    Length = Request->Data.WriteConsoleInputRequest.Length;
2415    Size = Length * sizeof(INPUT_RECORD);
2416    
2417     if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2418          || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2419    {
2420       UNLOCK;
2421       Reply->Status = STATUS_ACCESS_VIOLATION;
2422       return Reply->Status ;
2423    }
2424    
2425    for(i = 0; i < Length; ++i)
2426    {
2427       Record = RtlAllocateHeap(CsrssApiHeap, 0, sizeof(ConsoleInput));
2428       if(Record == NULL)
2429       {
2430          UNLOCK;
2431          Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
2432          return Reply->Status;
2433       }
2434       
2435       Record->InputEvent = *InputRecord++;
2436       InsertTailList(&Console->InputEvents, &Record->ListEntry);
2437    }
2438       
2439    UNLOCK;
2440    
2441    Reply->Status = STATUS_SUCCESS;
2442    Reply->Data.WriteConsoleInputReply.Length = i;
2443    return Reply->Status;
2444 }
2445
2446 /* EOF */