KERNEL32.GetConsoleWindow implemented
[reactos.git] / reactos / subsys / csrss / api / conio.c
1 /* $Id: conio.c,v 1.48 2003/06/19 19:38:26 ea Exp $
2 *
3 * reactos/subsys/csrss/api/conio.c
4 *
5 * Console I/O functions
6 *
7 * ReactOS Operating System
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ddk/ntddk.h>
13
14 #include <csrss/csrss.h>
15 #include "api.h"
16 #include <ntdll/rtl.h>
17 #include <ddk/ntddblue.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22 #define LOCK RtlEnterCriticalSection(&ActiveConsoleLock)
23 #define UNLOCK RtlLeaveCriticalSection(&ActiveConsoleLock)
24
25 /* FIXME: Is there a way to create real aliasses with gcc? [CSH] */
26 #define ALIAS(Name, Target) typeof(Target) Name = Target
27
28
29 /* GLOBALS *******************************************************************/
30
31 static HANDLE ConsoleDeviceHandle;
32 static HANDLE KeyboardDeviceHandle;
33 static PCSRSS_CONSOLE ActiveConsole;
34 CRITICAL_SECTION ActiveConsoleLock;
35 static COORD PhysicalConsoleSize;
36
37 /* FUNCTIONS *****************************************************************/
38
39 CSR_API(CsrAllocConsole)
40 {
41 PCSRSS_CONSOLE Console;
42 HANDLE Process;
43 NTSTATUS Status;
44 CLIENT_ID ClientId;
45
46 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
47 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
48 sizeof(LPC_MESSAGE);
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 /* Create the GDI Window to be used in windowed mode */
761 /* FIXME: create window; now write NULL */
762 Console->hWindow = (HWND) NULL;
763 /* add a reference count because the buffer is tied to the console */
764 Console->ActiveBuffer->Header.ReferenceCount++;
765 /* make console active, and insert into console list */
766 LOCK;
767 if( ActiveConsole )
768 {
769 Console->Prev = ActiveConsole;
770 Console->Next = ActiveConsole->Next;
771 ActiveConsole->Next->Prev = Console;
772 ActiveConsole->Next = Console;
773 }
774 else {
775 Console->Prev = Console;
776 Console->Next = Console;
777 }
778 ActiveConsole = Console;
779 /* copy buffer contents to screen */
780 CsrDrawConsole( Console->ActiveBuffer );
781 UNLOCK;
782 return STATUS_SUCCESS;
783 }
784
785 /***************************************************************
786 * CsrDrawConsole blasts the console buffer onto the screen *
787 * must be called while holding the active console lock *
788 **************************************************************/
789 VOID STDCALL CsrDrawConsole( PCSRSS_SCREEN_BUFFER Buff )
790 {
791 SMALL_RECT Region;
792
793 CsrpInitRect(
794 Region,
795 0,
796 0,
797 PhysicalConsoleSize.Y - 1,
798 PhysicalConsoleSize.X - 1);
799
800 CsrpDrawRegion(Buff, Region);
801 }
802
803
804 VOID STDCALL CsrDeleteConsole( PCSRSS_CONSOLE Console )
805 {
806 ConsoleInput *Event;
807 DPRINT( "CsrDeleteConsole\n" );
808 LOCK;
809 /* Drain input event queue */
810 while( Console->InputEvents.Flink != &Console->InputEvents )
811 {
812 Event = (ConsoleInput *)Console->InputEvents.Flink;
813 Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
814 Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
815 RtlFreeHeap( CsrssApiHeap, 0, Event );
816 }
817 /* Switch to next console */
818 if( ActiveConsole == Console )
819 {
820 if( Console->Next != Console )
821 {
822 ActiveConsole = Console->Next;
823 }
824 else ActiveConsole = 0;
825 }
826 if (Console->Next != Console)
827 {
828 Console->Prev->Next = Console->Next;
829 Console->Next->Prev = Console->Prev;
830 }
831
832 if( ActiveConsole )
833 CsrDrawConsole( ActiveConsole->ActiveBuffer );
834 if( !--Console->ActiveBuffer->Header.ReferenceCount )
835 CsrDeleteScreenBuffer( Console->ActiveBuffer );
836 UNLOCK;
837 NtClose( Console->ActiveEvent );
838 RtlFreeUnicodeString( &Console->Title );
839 RtlFreeHeap( CsrssApiHeap, 0, Console );
840 }
841
842 VOID STDCALL CsrInitConsoleSupport(VOID)
843 {
844 OBJECT_ATTRIBUTES ObjectAttributes;
845 UNICODE_STRING DeviceName;
846 NTSTATUS Status;
847 IO_STATUS_BLOCK Iosb;
848 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
849
850 DPRINT("CSR: CsrInitConsoleSupport()\n");
851
852 RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\BlueScreen");
853 InitializeObjectAttributes(&ObjectAttributes,
854 &DeviceName,
855 0,
856 NULL,
857 NULL);
858 Status = NtOpenFile(&ConsoleDeviceHandle,
859 FILE_ALL_ACCESS,
860 &ObjectAttributes,
861 &Iosb,
862 0,
863 FILE_SYNCHRONOUS_IO_ALERT);
864 if (!NT_SUCCESS(Status))
865 {
866 DbgPrint("CSR: Failed to open console. Expect problems.\n");
867 }
868
869 RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\Keyboard");
870 InitializeObjectAttributes(&ObjectAttributes,
871 &DeviceName,
872 0,
873 NULL,
874 NULL);
875 Status = NtOpenFile(&KeyboardDeviceHandle,
876 FILE_ALL_ACCESS,
877 &ObjectAttributes,
878 &Iosb,
879 0,
880 0);
881 if (!NT_SUCCESS(Status))
882 {
883 DbgPrint("CSR: Failed to open keyboard. Expect problems.\n");
884 }
885
886 ActiveConsole = 0;
887 RtlInitializeCriticalSection( &ActiveConsoleLock );
888 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, &ScrInfo, sizeof( ScrInfo ) );
889 if( !NT_SUCCESS( Status ) )
890 {
891 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
892 return;
893 }
894 PhysicalConsoleSize = ScrInfo.dwSize;
895 }
896
897 VOID Console_Api( DWORD RefreshEvent )
898 {
899 /* keep reading events from the keyboard and stuffing them into the current
900 console's input queue */
901 ConsoleInput *KeyEventRecord;
902 ConsoleInput *TempInput;
903 IO_STATUS_BLOCK Iosb;
904 NTSTATUS Status;
905 HANDLE Events[2]; // 0 = keyboard, 1 = refresh
906 int c;
907 int updown;
908 PCSRSS_CONSOLE SwapConsole = 0; // console we are thinking about swapping with
909
910 Events[0] = 0;
911 Status = NtCreateEvent( &Events[0], STANDARD_RIGHTS_ALL, NULL, FALSE, FALSE );
912 if( !NT_SUCCESS( Status ) )
913 {
914 DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status );
915 NtTerminateProcess( NtCurrentProcess(), Status );
916 }
917 Events[1] = (HANDLE)RefreshEvent;
918 while( 1 )
919 {
920 KeyEventRecord = RtlAllocateHeap(CsrssApiHeap,
921 0,
922 sizeof(ConsoleInput));
923 if ( KeyEventRecord == 0 )
924 {
925 DbgPrint( "CSR: Memory allocation failure!" );
926 continue;
927 }
928 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
929 Status = NtReadFile( KeyboardDeviceHandle, Events[0], NULL, NULL, &Iosb,
930 &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 );
931 if( !NT_SUCCESS( Status ) )
932 {
933 DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
934 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
935 continue;
936 }
937 if( Status == STATUS_PENDING )
938 {
939 while( 1 )
940 {
941 Status = NtWaitForMultipleObjects( 2, Events, WaitAny, FALSE, NULL );
942 if( Status == STATUS_WAIT_0 + 1 )
943 {
944 LOCK;
945 CsrDrawConsole( ActiveConsole->ActiveBuffer );
946 UNLOCK;
947 continue;
948 }
949 else if( Status != STATUS_WAIT_0 )
950 {
951 DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status );
952 NtTerminateProcess( NtCurrentProcess(), Status );
953 }
954 else break;
955 }
956 }
957 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
958 ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED )&&
959 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_TAB )
960 if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
961 {
962 ANSI_STRING Title;
963 void * Buffer;
964 COORD *pos;
965
966 /* alt-tab, swap consoles */
967 // move SwapConsole to next console, and print its title
968 LOCK;
969 if( !SwapConsole )
970 SwapConsole = ActiveConsole;
971
972 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED )
973 SwapConsole = SwapConsole->Prev;
974 else SwapConsole = SwapConsole->Next;
975 Title.MaximumLength = RtlUnicodeStringToAnsiSize( &SwapConsole->Title );
976 Title.Length = 0;
977 Buffer = RtlAllocateHeap( CsrssApiHeap,
978 0,
979 sizeof( COORD ) + Title.MaximumLength);
980 pos = (COORD *)Buffer;
981 Title.Buffer = Buffer + sizeof( COORD );
982
983 RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Title, FALSE);
984 pos->Y = PhysicalConsoleSize.Y / 2;
985 pos->X = ( PhysicalConsoleSize.X - Title.Length ) / 2;
986 // redraw the console to clear off old title
987 CsrDrawConsole( ActiveConsole->ActiveBuffer );
988 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
989 NULL,
990 NULL,
991 NULL,
992 &Iosb,
993 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
994 Buffer,
995 sizeof (COORD) + Title.Length,
996 NULL,
997 0);
998 if( !NT_SUCCESS( Status ) )
999 {
1000 DPRINT1( "Error writing to console\n" );
1001 }
1002 RtlFreeHeap( CsrssApiHeap, 0, Buffer );
1003
1004 UNLOCK;
1005 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1006 continue;
1007 }
1008 else {
1009 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1010 continue;
1011 }
1012 else if( SwapConsole &&
1013 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_MENU &&
1014 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == FALSE )
1015 {
1016 // alt key released, swap consoles
1017 PCSRSS_CONSOLE tmp;
1018
1019 LOCK;
1020 if( SwapConsole != ActiveConsole )
1021 {
1022 // first remove swapconsole from the list
1023 SwapConsole->Prev->Next = SwapConsole->Next;
1024 SwapConsole->Next->Prev = SwapConsole->Prev;
1025 // now insert before activeconsole
1026 SwapConsole->Next = ActiveConsole;
1027 SwapConsole->Prev = ActiveConsole->Prev;
1028 ActiveConsole->Prev->Next = SwapConsole;
1029 ActiveConsole->Prev = SwapConsole;
1030 }
1031 ActiveConsole = SwapConsole;
1032 SwapConsole = 0;
1033 CsrDrawConsole( ActiveConsole->ActiveBuffer );
1034
1035 UNLOCK;
1036 }
1037 if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
1038 ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) &&
1039 ( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP ||
1040 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) )
1041 {
1042 if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE )
1043 {
1044 /* scroll up or down */
1045 LOCK;
1046 if( ActiveConsole == 0 )
1047 {
1048 DbgPrint( "CSR: No Active Console!\n" );
1049 UNLOCK;
1050 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1051 continue;
1052 }
1053 if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP )
1054 {
1055 /* only scroll up if there is room to scroll up into */
1056 if( ActiveConsole->ActiveBuffer->ShowY != ((ActiveConsole->ActiveBuffer->CurrentY + 1) %
1057 ActiveConsole->ActiveBuffer->MaxY) )
1058 ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY +
1059 ActiveConsole->ActiveBuffer->MaxY - 1) % ActiveConsole->ActiveBuffer->MaxY;
1060 }
1061 else if( ActiveConsole->ActiveBuffer->ShowY != ActiveConsole->ActiveBuffer->CurrentY )
1062 /* only scroll down if there is room to scroll down into */
1063 if( ActiveConsole->ActiveBuffer->ShowY % ActiveConsole->ActiveBuffer->MaxY !=
1064 ActiveConsole->ActiveBuffer->CurrentY )
1065
1066 if( ((ActiveConsole->ActiveBuffer->CurrentY + 1) % ActiveConsole->ActiveBuffer->MaxY) !=
1067 (ActiveConsole->ActiveBuffer->ShowY + PhysicalConsoleSize.Y) % ActiveConsole->ActiveBuffer->MaxY )
1068 ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY + 1) %
1069 ActiveConsole->ActiveBuffer->MaxY;
1070 CsrDrawConsole( ActiveConsole->ActiveBuffer );
1071 UNLOCK;
1072 }
1073 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1074 continue;
1075 }
1076 LOCK;
1077 if( ActiveConsole == 0 )
1078 {
1079 DbgPrint( "CSR: No Active Console!\n" );
1080 UNLOCK;
1081 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1082 continue;
1083 }
1084 // process special keys if enabled
1085 if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) )
1086 switch( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar )
1087 {
1088 case '\r':
1089 // add a \n to the queue as well
1090 // first add the \r
1091 updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
1092 KeyEventRecord->Echoed = FALSE;
1093 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
1094 InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1095 ActiveConsole->WaitingChars++;
1096 KeyEventRecord = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( ConsoleInput ) );
1097 if( !KeyEventRecord )
1098 {
1099 DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" );
1100 UNLOCK;
1101 continue;
1102 }
1103 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1104 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
1105 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
1106 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
1107 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
1108 }
1109 // add event to the queue
1110 InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry);
1111 // if line input mode is enabled, only wake the client on enter key down
1112 if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT ) ||
1113 ActiveConsole->EarlyReturn ||
1114 ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' &&
1115 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) )
1116 {
1117 NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1118 if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1119 ActiveConsole->WaitingLines++;
1120 }
1121 KeyEventRecord->Echoed = FALSE;
1122 if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) &&
1123 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' &&
1124 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown )
1125 {
1126 // walk the input queue looking for a char to backspace
1127 for( TempInput = (ConsoleInput *)ActiveConsole->InputEvents.Blink;
1128 TempInput != (ConsoleInput *)&ActiveConsole->InputEvents &&
1129 (TempInput->InputEvent.EventType != KEY_EVENT ||
1130 TempInput->InputEvent.Event.KeyEvent.bKeyDown == FALSE ||
1131 TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' );
1132 TempInput = (ConsoleInput *)TempInput->ListEntry.Blink );
1133 // if we found one, delete it, otherwise, wake the client
1134 if( TempInput != (ConsoleInput *)&ActiveConsole->InputEvents )
1135 {
1136 // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue
1137 RemoveEntryList(&TempInput->ListEntry);
1138 if( TempInput->Echoed )
1139 CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1140 RtlFreeHeap( CsrssApiHeap, 0, TempInput );
1141 RemoveEntryList(&KeyEventRecord->ListEntry);
1142 RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
1143 ActiveConsole->WaitingChars -= 2;
1144 }
1145 else NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1146 }
1147 else {
1148 // echo chars if we are supposed to and client is waiting for some
1149 if( ( ActiveConsole->Mode & ENABLE_ECHO_INPUT ) && ActiveConsole->EchoCount &&
1150 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar &&
1151 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE &&
1152 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' )
1153 {
1154 // mark the char as already echoed
1155 CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE );
1156 ActiveConsole->EchoCount--;
1157 KeyEventRecord->Echoed = TRUE;
1158 }
1159 }
1160 ActiveConsole->WaitingChars++;
1161 if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT) )
1162 NtSetEvent( ActiveConsole->ActiveEvent, 0 );
1163 UNLOCK;
1164 }
1165 }
1166
1167 CSR_API(CsrGetScreenBufferInfo)
1168 {
1169 NTSTATUS Status;
1170 PCSRSS_SCREEN_BUFFER Buff;
1171 PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1172 IO_STATUS_BLOCK Iosb;
1173
1174 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1175 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1176 sizeof(LPC_MESSAGE);
1177
1178 LOCK;
1179 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle,
1180 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1181 {
1182 UNLOCK;
1183 return Reply->Status = STATUS_INVALID_HANDLE;
1184 }
1185 pInfo = &Reply->Data.ScreenBufferInfoReply.Info;
1186 if( Buff == ActiveConsole->ActiveBuffer )
1187 {
1188 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1189 IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, pInfo, sizeof( *pInfo ) );
1190 if( !NT_SUCCESS( Status ) )
1191 DbgPrint( "CSR: Failed to get console info, expect trouble\n" );
1192 Reply->Status = Status;
1193 }
1194 else {
1195 pInfo->dwSize.X = PhysicalConsoleSize.X;
1196 pInfo->dwSize.Y = PhysicalConsoleSize.Y;
1197 pInfo->dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1198 pInfo->dwCursorPosition.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1199 pInfo->wAttributes = Buff->DefaultAttrib;
1200 pInfo->srWindow.Left = 0;
1201 pInfo->srWindow.Right = PhysicalConsoleSize.X - 1;
1202 pInfo->srWindow.Top = 0;
1203 pInfo->srWindow.Bottom = PhysicalConsoleSize.Y - 1;
1204 Reply->Status = STATUS_SUCCESS;
1205 }
1206 UNLOCK;
1207 return Reply->Status;
1208 }
1209
1210 CSR_API(CsrSetCursor)
1211 {
1212 NTSTATUS Status;
1213 PCSRSS_SCREEN_BUFFER Buff;
1214 CONSOLE_SCREEN_BUFFER_INFO Info;
1215 IO_STATUS_BLOCK Iosb;
1216
1217 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1218 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1219 sizeof(LPC_MESSAGE);
1220
1221 LOCK;
1222 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.SetCursorRequest.ConsoleHandle,
1223 (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1224 {
1225 UNLOCK;
1226 return Reply->Status = STATUS_INVALID_HANDLE;
1227 }
1228 Info.dwCursorPosition = Request->Data.SetCursorRequest.Position;
1229 Info.wAttributes = Buff->DefaultAttrib;
1230 if( Buff == ActiveConsole->ActiveBuffer )
1231 {
1232 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb,
1233 IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &Info, sizeof( Info ), 0, 0 );
1234 if( !NT_SUCCESS( Status ) )
1235 DbgPrint( "CSR: Failed to set console info, expect trouble\n" );
1236 }
1237
1238 Buff->CurrentX = Info.dwCursorPosition.X + Buff->ShowX;
1239 Buff->CurrentY = (Info.dwCursorPosition.Y + Buff->ShowY) % Buff->MaxY;
1240 UNLOCK;
1241 return Reply->Status = Status;
1242 }
1243
1244 CSR_API(CsrWriteConsoleOutputChar)
1245 {
1246 PBYTE String = Request->Data.WriteConsoleOutputCharRequest.String;
1247 PBYTE Buffer;
1248 PCSRSS_SCREEN_BUFFER Buff;
1249 DWORD X, Y, Length;
1250 NTSTATUS Status;
1251 IO_STATUS_BLOCK Iosb;
1252
1253 DPRINT("CsrWriteConsoleOutputChar\n");
1254
1255 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1256 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1257 sizeof(LPC_MESSAGE);
1258 LOCK;
1259 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1260 {
1261 UNLOCK;
1262 return Reply->Status = STATUS_INVALID_HANDLE;
1263 }
1264
1265
1266 X = Request->Data.WriteConsoleOutputCharRequest.Coord.X + Buff->ShowX;
1267 Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1268 Length = Request->Data.WriteConsoleOutputCharRequest.Length;
1269 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1270 while(Length--)
1271 {
1272 *Buffer = *String++;
1273 Buffer += 2;
1274 if (++X == Buff->MaxX)
1275 {
1276 if (++Y == Buff->MaxY)
1277 {
1278 Y = 0;
1279 Buffer = Buff->Buffer;
1280 }
1281 X = 0;
1282 }
1283 }
1284 if( ActiveConsole->ActiveBuffer == Buff )
1285 {
1286 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1287 NULL,
1288 NULL,
1289 NULL,
1290 &Iosb,
1291 IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
1292 &Request->Data.WriteConsoleOutputCharRequest.Coord,
1293 sizeof (COORD) + Request->Data.WriteConsoleOutputCharRequest.Length,
1294 NULL,
1295 0);
1296 if( !NT_SUCCESS( Status ) )
1297 DPRINT1( "Failed to write output chars: %x\n", Status );
1298 }
1299 Reply->Data.WriteConsoleOutputCharReply.EndCoord.X = X - Buff->ShowX;
1300 Reply->Data.WriteConsoleOutputCharReply.EndCoord.Y = (Y + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1301 UNLOCK;
1302 return Reply->Status = STATUS_SUCCESS;
1303 }
1304
1305 CSR_API(CsrFillOutputChar)
1306 {
1307 PCSRSS_SCREEN_BUFFER Buff;
1308 DWORD X, Y, Length;
1309 BYTE Char;
1310 OUTPUT_CHARACTER Character;
1311 PBYTE Buffer;
1312 NTSTATUS Status;
1313 IO_STATUS_BLOCK Iosb;
1314
1315 DPRINT("CsrFillOutputChar\n");
1316
1317 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1318 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1319 sizeof(LPC_MESSAGE);
1320
1321 LOCK;
1322 if( !NT_SUCCESS( CsrGetObject( ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, (Object_t **)&Buff ) ) || Buff->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC )
1323 {
1324 UNLOCK;
1325 return Reply->Status = STATUS_INVALID_HANDLE;
1326 }
1327 X = Request->Data.FillOutputRequest.Position.X + Buff->ShowX;
1328 Y = (Request->Data.FillOutputRequest.Position.Y + Buff->ShowY) % Buff->MaxY;
1329 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1330 Char = Request->Data.FillOutputRequest.Char;
1331 Length = Request->Data.FillOutputRequest.Length;
1332 while (Length--)
1333 {
1334 *Buffer = Char;
1335 Buffer += 2;
1336 if( ++X == Buff->MaxX )
1337 {
1338 if( ++Y == Buff->MaxY )
1339 {
1340 Y = 0;
1341 Buffer = Buff->Buffer;
1342 }
1343 X = 0;
1344 }
1345 }
1346 if( Buff == ActiveConsole->ActiveBuffer )
1347 {
1348 Character.dwCoord = Request->Data.FillOutputRequest.Position;
1349 Character.cCharacter = Char;
1350 Character.nLength = Request->Data.FillOutputRequest.Length;
1351 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1352 NULL,
1353 NULL,
1354 NULL,
1355 &Iosb,
1356 IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER,
1357 &Character,
1358 sizeof(Character),
1359 NULL,
1360 0);
1361 if (!NT_SUCCESS(Status))
1362 DPRINT1( "Failed to write output characters to console\n" );
1363 }
1364 UNLOCK;
1365 return Reply->Status;
1366 }
1367
1368 CSR_API(CsrReadInputEvent)
1369 {
1370 PLIST_ENTRY CurrentEntry;
1371 PCSRSS_CONSOLE Console;
1372 NTSTATUS Status;
1373 ConsoleInput *Input;
1374
1375 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1376 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1377 sizeof(LPC_MESSAGE);
1378 Reply->Data.ReadInputReply.Event = ProcessData->ConsoleEvent;
1379
1380 LOCK;
1381 Status = CsrGetObject( ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, (Object_t **)&Console );
1382 if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? 0 : STATUS_INVALID_HANDLE))
1383 {
1384 Reply->Status = Status;
1385 UNLOCK;
1386 return Status;
1387 }
1388
1389 // only get input if there is any
1390 if( Console->InputEvents.Flink != &Console->InputEvents )
1391 {
1392 CurrentEntry = RemoveHeadList(&Console->InputEvents);
1393 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1394 Reply->Data.ReadInputReply.Input = Input->InputEvent;
1395
1396 if( Input->InputEvent.EventType == KEY_EVENT )
1397 {
1398 if( Console->Mode & ENABLE_LINE_INPUT &&
1399 Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE &&
1400 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1401 Console->WaitingLines--;
1402 Console->WaitingChars--;
1403 }
1404 RtlFreeHeap( CsrssApiHeap, 0, Input );
1405
1406 if (Console->InputEvents.Flink != &Console->InputEvents &&
1407 Reply->Data.ReadInputReply.Input.EventType == KEY_EVENT &&
1408 Reply->Data.ReadInputReply.Input.Event.KeyEvent.uChar.AsciiChar == '\r')
1409 {
1410 Input = CONTAINING_RECORD(Console->InputEvents.Flink, ConsoleInput, ListEntry);
1411 if (Input->InputEvent.EventType == KEY_EVENT &&
1412 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' &&
1413 ((Input->InputEvent.Event.KeyEvent.bKeyDown && Reply->Data.ReadInputReply.Input.Event.KeyEvent.bKeyDown) ||
1414 (Input->InputEvent.Event.KeyEvent.bKeyDown==FALSE && Reply->Data.ReadInputReply.Input.Event.KeyEvent.bKeyDown==FALSE)))
1415 {
1416 if(Console->Mode & ENABLE_LINE_INPUT &&
1417 Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE &&
1418 Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' )
1419 Console->WaitingLines--;
1420 Console->WaitingChars--;
1421 RemoveHeadList(&Console->InputEvents);
1422 RtlFreeHeap( CsrssApiHeap, 0, Input );
1423 }
1424 }
1425
1426 Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents) ? TRUE : FALSE;
1427 Status = STATUS_SUCCESS;
1428 Console->EarlyReturn = FALSE; // clear early return
1429 }
1430 else {
1431 Status = STATUS_PENDING;
1432 Console->EarlyReturn = TRUE; // mark for early return
1433 }
1434 UNLOCK;
1435 return Reply->Status = Status;
1436 }
1437
1438 CSR_API(CsrWriteConsoleOutputAttrib)
1439 {
1440 PCSRSS_SCREEN_BUFFER Buff;
1441 PUCHAR Buffer, Attribute;
1442 NTSTATUS Status;
1443 int X, Y, Length;
1444 IO_STATUS_BLOCK Iosb;
1445
1446 DPRINT("CsrWriteConsoleOutputAttrib\n");
1447
1448 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1449 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1450 sizeof(LPC_MESSAGE);
1451 LOCK;
1452 Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1453 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1454 {
1455 Reply->Status = Status;
1456 UNLOCK;
1457 return Status;
1458 }
1459 X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X + Buff->ShowX;
1460 Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1461 Length = Request->Data.WriteConsoleOutputAttribRequest.Length;
1462 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
1463 Attribute = Request->Data.WriteConsoleOutputAttribRequest.String;
1464 while (Length--)
1465 {
1466 *Buffer = *Attribute++;
1467 Buffer += 2;
1468 if( ++X == Buff->MaxX )
1469 {
1470 X = 0;
1471 if( ++Y == Buff->MaxY )
1472 {
1473 Y = 0;
1474 Buffer = Buff->Buffer + 1;
1475 }
1476 }
1477 }
1478 if( Buff == ActiveConsole->ActiveBuffer )
1479 {
1480 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1481 NULL,
1482 NULL,
1483 NULL,
1484 &Iosb,
1485 IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE,
1486 &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1487 Request->Data.WriteConsoleOutputAttribRequest.Length +
1488 sizeof (COORD),
1489 NULL,
1490 0 );
1491 if( !NT_SUCCESS( Status ) )
1492 DPRINT1( "Failed to write output attributes to console\n" );
1493 }
1494 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1495 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.Y = ( Buff->CurrentY + Buff->MaxY - Buff->ShowY ) % Buff->MaxY;
1496 UNLOCK;
1497 return Reply->Status = STATUS_SUCCESS;
1498 }
1499
1500 CSR_API(CsrFillOutputAttrib)
1501 {
1502 OUTPUT_ATTRIBUTE Attribute;
1503 PCSRSS_SCREEN_BUFFER Buff;
1504 PCHAR Buffer;
1505 NTSTATUS Status;
1506 int X, Y, Length;
1507 IO_STATUS_BLOCK Iosb;
1508 UCHAR Attr;
1509
1510 DPRINT("CsrFillOutputAttrib\n");
1511
1512 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1513 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1514 sizeof(LPC_MESSAGE);
1515 LOCK;
1516 Status = CsrGetObject( ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1517 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1518 {
1519 Reply->Status = Status;
1520 UNLOCK;
1521 return Status;
1522 }
1523 X = Request->Data.FillOutputAttribRequest.Coord.X + Buff->ShowX;
1524 Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1525 Length = Request->Data.FillOutputAttribRequest.Length;
1526 Attr = Request->Data.FillOutputAttribRequest.Attribute;
1527 Buffer = &Buff->Buffer[(Y * Buff->MaxX * 2) + (X * 2) + 1];
1528 while(Length--)
1529 {
1530 *Buffer = Attr;
1531 Buffer += 2;
1532 if( ++X == Buff->MaxX )
1533 {
1534 X = 0;
1535 if( ++Y == Buff->MaxY )
1536 {
1537 Y = 0;
1538 Buffer = Buff->Buffer + 1;
1539 }
1540 }
1541 }
1542 if( Buff == ActiveConsole->ActiveBuffer )
1543 {
1544 Attribute.wAttribute = Attr;
1545 Attribute.nLength = Request->Data.FillOutputAttribRequest.Length;
1546 Attribute.dwCoord = Request->Data.FillOutputAttribRequest.Coord;
1547 Status = NtDeviceIoControlFile( ConsoleDeviceHandle,
1548 NULL,
1549 NULL,
1550 NULL,
1551 &Iosb,
1552 IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE,
1553 &Attribute,
1554 sizeof(OUTPUT_ATTRIBUTE),
1555 NULL,
1556 0);
1557 if( !NT_SUCCESS( Status ) )
1558 DPRINT1( "Failed to fill output attributes to console\n" );
1559 }
1560 UNLOCK;
1561 return Reply->Status = STATUS_SUCCESS;
1562 }
1563
1564
1565 CSR_API(CsrGetCursorInfo)
1566 {
1567 PCSRSS_SCREEN_BUFFER Buff;
1568 NTSTATUS Status;
1569
1570 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1571 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1572 sizeof(LPC_MESSAGE);
1573 LOCK;
1574 Status = CsrGetObject( ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1575 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1576 {
1577 Reply->Status = Status;
1578 UNLOCK;
1579 return Status;
1580 }
1581 Reply->Data.GetCursorInfoReply.Info = Buff->CursorInfo;
1582 UNLOCK;
1583 return Reply->Status = STATUS_SUCCESS;
1584 }
1585
1586 CSR_API(CsrSetCursorInfo)
1587 {
1588 PCSRSS_SCREEN_BUFFER Buff;
1589 NTSTATUS Status;
1590 IO_STATUS_BLOCK Iosb;
1591
1592 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1593 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1594 sizeof(LPC_MESSAGE);
1595 LOCK;
1596 Status = CsrGetObject( ProcessData,
1597 Request->Data.SetCursorInfoRequest.ConsoleHandle, (Object_t **)&Buff );
1598
1599 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1600 {
1601 Reply->Status = Status;
1602 UNLOCK;
1603 return Status;
1604 }
1605 Buff->CursorInfo = Request->Data.SetCursorInfoRequest.Info;
1606 if( Buff == ActiveConsole->ActiveBuffer )
1607 {
1608 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_CURSOR_INFO, &Buff->CursorInfo, sizeof( Buff->CursorInfo ), 0, 0 );
1609 if( !NT_SUCCESS( Status ) )
1610 {
1611 DbgPrint( "CSR: Failed to set cursor info\n" );
1612 return Reply->Status = Status;
1613 }
1614 }
1615 UNLOCK;
1616 return Reply->Status = STATUS_SUCCESS;
1617 }
1618
1619 CSR_API(CsrSetTextAttrib)
1620 {
1621 NTSTATUS Status;
1622 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
1623 IO_STATUS_BLOCK Iosb;
1624 PCSRSS_SCREEN_BUFFER Buff;
1625
1626 DPRINT("CsrSetTextAttrib\n");
1627
1628 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1629 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1630 sizeof(LPC_MESSAGE);
1631 LOCK;
1632 Status = CsrGetObject( ProcessData, Request->Data.SetAttribRequest.ConsoleHandle, (Object_t **)&Buff );
1633 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? 0 : STATUS_INVALID_HANDLE ))
1634 {
1635 Reply->Status = Status;
1636 UNLOCK;
1637 return Status;
1638 }
1639 Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1640 if( Buff == ActiveConsole->ActiveBuffer )
1641 {
1642 ScrInfo.wAttributes = Buff->DefaultAttrib;
1643 ScrInfo.dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1644 ScrInfo.dwCursorPosition.Y = ((Buff->CurrentY + Buff->MaxY) - Buff->ShowY) % Buff->MaxY;
1645 Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO, &ScrInfo, sizeof( ScrInfo ), 0, 0 );
1646 if( !NT_SUCCESS( Status ) )
1647 {
1648 DbgPrint( "CSR: Failed to set console info\n" );
1649 UNLOCK;
1650 return Reply->Status = Status;
1651 }
1652 }
1653 UNLOCK;
1654 return Reply->Status = STATUS_SUCCESS;
1655 }
1656
1657 CSR_API(CsrSetConsoleMode)
1658 {
1659 NTSTATUS Status;
1660 PCSRSS_CONSOLE Console;
1661 PCSRSS_SCREEN_BUFFER Buff;
1662
1663 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1664 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1665 LOCK;
1666 Status = CsrGetObject( ProcessData,
1667 Request->Data.SetConsoleModeRequest.ConsoleHandle,
1668 (Object_t **)&Console );
1669 if( !NT_SUCCESS( Status ) )
1670 {
1671 Reply->Status = Status;
1672 UNLOCK;
1673 return Status;
1674 }
1675
1676 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1677 if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1678 Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1679 else if( Console->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1680 Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1681 else {
1682 Reply->Status = STATUS_INVALID_HANDLE;
1683 UNLOCK;
1684 return Status;
1685 }
1686 UNLOCK;
1687 Reply->Status = STATUS_SUCCESS;
1688 return Reply->Status;
1689 }
1690
1691 CSR_API(CsrGetConsoleMode)
1692 {
1693 NTSTATUS Status;
1694 PCSRSS_CONSOLE Console;
1695 PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
1696
1697 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1698 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1699 LOCK;
1700 Status = CsrGetObject( ProcessData,
1701 Request->Data.GetConsoleModeRequest.ConsoleHandle,
1702 (Object_t **)&Console );
1703 if( !NT_SUCCESS( Status ) )
1704 {
1705 Reply->Status = Status;
1706 UNLOCK;
1707 return Status;
1708 }
1709 Reply->Status = STATUS_SUCCESS;
1710 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1711 if( Console->Header.Type == CSRSS_CONSOLE_MAGIC )
1712 Reply->Data.GetConsoleModeReply.ConsoleMode = Console->Mode;
1713 else if( Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC )
1714 Reply->Data.GetConsoleModeReply.ConsoleMode = Buff->Mode;
1715 else Status = STATUS_INVALID_HANDLE;
1716 UNLOCK;
1717 return Reply->Status;
1718 }
1719
1720 CSR_API(CsrCreateScreenBuffer)
1721 {
1722 PCSRSS_SCREEN_BUFFER Buff;
1723 NTSTATUS Status;
1724
1725 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1726 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1727
1728 if (ProcessData == NULL)
1729 {
1730 return(Reply->Status = STATUS_INVALID_PARAMETER);
1731 }
1732
1733 Buff = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( CSRSS_SCREEN_BUFFER ) );
1734 if( !Buff )
1735 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
1736 LOCK;
1737 Status = CsrInitConsoleScreenBuffer( Buff );
1738 if( !NT_SUCCESS( Status ) )
1739 Reply->Status = Status;
1740 else {
1741 Status = CsrInsertObject( ProcessData, &Reply->Data.CreateScreenBufferReply.OutputHandle, &Buff->Header );
1742 if( !NT_SUCCESS( Status ) )
1743 Reply->Status = Status;
1744 else Reply->Status = STATUS_SUCCESS;
1745 }
1746 UNLOCK;
1747 return Reply->Status;
1748 }
1749
1750 CSR_API(CsrSetScreenBuffer)
1751 {
1752 NTSTATUS Status;
1753 PCSRSS_SCREEN_BUFFER Buff;
1754
1755 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1756 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1757 LOCK;
1758 Status = CsrGetObject( ProcessData, Request->Data.SetActiveScreenBufferRequest.OutputHandle, (Object_t **)&Buff );
1759 if( !NT_SUCCESS( Status ) )
1760 Reply->Status = Status;
1761 else {
1762 // drop reference to old buffer, maybe delete
1763 if( !InterlockedDecrement( &ProcessData->Console->ActiveBuffer->Header.ReferenceCount ) )
1764 CsrDeleteScreenBuffer( ProcessData->Console->ActiveBuffer );
1765 // tie console to new buffer
1766 ProcessData->Console->ActiveBuffer = Buff;
1767 // inc ref count on new buffer
1768 InterlockedIncrement( &Buff->Header.ReferenceCount );
1769 // if the console is active, redraw it
1770 if( ActiveConsole == ProcessData->Console )
1771 CsrDrawConsole( Buff );
1772 Reply->Status = STATUS_SUCCESS;
1773 }
1774 UNLOCK;
1775 return Reply->Status;
1776 }
1777
1778 CSR_API(CsrSetTitle)
1779 {
1780 NTSTATUS Status;
1781 PCSRSS_CONSOLE Console;
1782
1783 Reply->Header.MessageSize = sizeof( CSRSS_API_REPLY );
1784 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1785 LOCK;
1786 Status = CsrGetObject( ProcessData, Request->Data.SetTitleRequest.Console, (Object_t **)&Console );
1787 if( !NT_SUCCESS( Status ) )
1788 Reply->Status = Status;
1789 else {
1790 // copy title to console
1791 RtlFreeUnicodeString( &Console->Title );
1792 RtlCreateUnicodeString( &Console->Title, Request->Data.SetTitleRequest.Title );
1793 Reply->Status = STATUS_SUCCESS;
1794 }
1795 UNLOCK;
1796 return Reply->Status;
1797 }
1798
1799 CSR_API(CsrGetTitle)
1800 {
1801 NTSTATUS Status;
1802 PCSRSS_CONSOLE Console;
1803
1804 Reply->Header.MessageSize = sizeof (CSRSS_API_REPLY);
1805 Reply->Header.DataSize =
1806 sizeof (CSRSS_API_REPLY)
1807 - sizeof(LPC_MESSAGE);
1808 LOCK;
1809 Status = CsrGetObject (
1810 ProcessData,
1811 Request->Data.GetTitleRequest.ConsoleHandle,
1812 (Object_t **) & Console
1813 );
1814 if ( !NT_SUCCESS( Status ) )
1815 {
1816 Reply->Status = Status;
1817 }
1818 else
1819 {
1820 HANDLE ConsoleHandle = Request->Data.GetTitleRequest.ConsoleHandle;
1821
1822 /* Copy title of the console to the user title buffer */
1823 RtlZeroMemory (
1824 & Reply->Data.GetTitleReply,
1825 sizeof (CSRSS_GET_TITLE_REPLY)
1826 );
1827 Reply->Data.GetTitleReply.ConsoleHandle = ConsoleHandle;
1828 Reply->Data.GetTitleReply.Length = Console->Title.Length;
1829 wcscpy (Reply->Data.GetTitleReply.Title, Console->Title.Buffer);
1830 Reply->Header.MessageSize += Console->Title.Length;
1831 Reply->Header.DataSize += Console->Title.Length;
1832 Reply->Status = STATUS_SUCCESS;
1833 }
1834 UNLOCK;
1835 return Reply->Status;
1836 }
1837
1838 CSR_API(CsrWriteConsoleOutput)
1839 {
1840 SHORT i, X, Y, SizeX, SizeY;
1841 PCSRSS_SCREEN_BUFFER Buff;
1842 SMALL_RECT ScreenBuffer;
1843 CHAR_INFO* CurCharInfo;
1844 SMALL_RECT WriteRegion;
1845 CHAR_INFO* CharInfo;
1846 COORD BufferCoord;
1847 COORD BufferSize;
1848 NTSTATUS Status;
1849 DWORD Offset;
1850 DWORD PSize;
1851
1852 DPRINT("CsrWriteConsoleOutput\n");
1853
1854 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1855 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1856 LOCK;
1857 Status = CsrGetObject( ProcessData, Request->Data.WriteConsoleOutputRequest.ConsoleHandle, (Object_t **)&Buff );
1858 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1859 {
1860 Reply->Status = Status;
1861 UNLOCK;
1862 return Status;
1863 }
1864
1865 BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
1866 PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
1867 BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
1868 CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
1869 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
1870 (((PVOID)CharInfo + PSize) >
1871 (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
1872 {
1873 UNLOCK;
1874 Reply->Status = STATUS_ACCESS_VIOLATION;
1875 return(Reply->Status);
1876 }
1877 WriteRegion = Request->Data.WriteConsoleOutputRequest.WriteRegion;
1878
1879 SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(WriteRegion));
1880 SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(WriteRegion));
1881 WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
1882 WriteRegion.Right = WriteRegion.Left + SizeX - 1;
1883
1884 /* Make sure WriteRegion is inside the screen buffer */
1885 CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1886 if (!CsrpGetIntersection(&WriteRegion, ScreenBuffer, WriteRegion))
1887 {
1888 UNLOCK;
1889 /* It is okay to have a WriteRegion completely outside the screen buffer.
1890 No data is written then. */
1891 return (Reply->Status = STATUS_SUCCESS);
1892 }
1893
1894 for ( i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++ )
1895 {
1896 CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
1897 Offset = (((Y + Buff->ShowY) % Buff->MaxY) * Buff->MaxX + WriteRegion.Left) * 2;
1898 for ( X = WriteRegion.Left; X <= WriteRegion.Right; X++ )
1899 {
1900 SET_CELL_BUFFER(Buff, Offset, CurCharInfo->Char.AsciiChar, CurCharInfo->Attributes);
1901 CurCharInfo++;
1902 }
1903 }
1904
1905 if( Buff == ActiveConsole->ActiveBuffer )
1906 {
1907 CsrpDrawRegion( ActiveConsole->ActiveBuffer, WriteRegion );
1908 }
1909
1910 UNLOCK;
1911 Reply->Data.WriteConsoleOutputReply.WriteRegion.Right = WriteRegion.Left + SizeX - 1;
1912 Reply->Data.WriteConsoleOutputReply.WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
1913 Reply->Data.WriteConsoleOutputReply.WriteRegion.Left = WriteRegion.Left;
1914 Reply->Data.WriteConsoleOutputReply.WriteRegion.Top = WriteRegion.Top;
1915 return (Reply->Status = STATUS_SUCCESS);
1916 }
1917
1918 CSR_API(CsrFlushInputBuffer)
1919 {
1920 PLIST_ENTRY CurrentEntry;
1921 PLIST_ENTRY NextEntry;
1922 PCSRSS_CONSOLE Console;
1923 ConsoleInput* Input;
1924 NTSTATUS Status;
1925
1926 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1927 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1928 LOCK;
1929 Status = CsrGetObject( ProcessData, Request->Data.FlushInputBufferRequest.ConsoleInput, (Object_t **)&Console );
1930 if( !NT_SUCCESS( Status ) || (Status = Console->Header.Type == CSRSS_CONSOLE_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1931 {
1932 Reply->Status = Status;
1933 UNLOCK;
1934 return Status;
1935 }
1936
1937 /* Discard all entries in the input event queue */
1938 while (!IsListEmpty(&Console->InputEvents))
1939 {
1940 CurrentEntry = RemoveHeadList(&Console->InputEvents);
1941 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1942 /* Destroy the event */
1943 RtlFreeHeap( CsrssApiHeap, 0, Input );
1944 }
1945 Console->WaitingChars=0;
1946 UNLOCK;
1947
1948 return (Reply->Status = STATUS_SUCCESS);
1949 }
1950
1951 CSR_API(CsrScrollConsoleScreenBuffer)
1952 {
1953 SHORT i, X, Y, SizeX, SizeY;
1954 PCSRSS_SCREEN_BUFFER Buff;
1955 SMALL_RECT ScreenBuffer;
1956 SMALL_RECT SrcRegion;
1957 SMALL_RECT DstRegion;
1958 SMALL_RECT FillRegion;
1959 IO_STATUS_BLOCK Iosb;
1960 CHAR_INFO* CharInfo;
1961 NTSTATUS Status;
1962 DWORD SrcOffset;
1963 DWORD DstOffset;
1964 BOOLEAN DoFill;
1965
1966 ALIAS(ConsoleHandle,Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle);
1967 ALIAS(ScrollRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle);
1968 ALIAS(UseClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle);
1969 ALIAS(ClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle);
1970 ALIAS(DestinationOrigin,Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin);
1971 ALIAS(Fill,Request->Data.ScrollConsoleScreenBufferRequest.Fill);
1972
1973 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1974 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1975 LOCK;
1976 Status = CsrGetObject( ProcessData, ConsoleHandle, (Object_t **)&Buff );
1977 if( !NT_SUCCESS( Status ) || (Status = Buff->Header.Type == CSRSS_SCREEN_BUFFER_MAGIC ? STATUS_SUCCESS : STATUS_INVALID_HANDLE ))
1978 {
1979 Reply->Status = Status;
1980 UNLOCK;
1981 return Status;
1982 }
1983
1984 /* Make sure source rectangle is inside the screen buffer */
1985 CsrpInitRect(ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
1986 if (!CsrpGetIntersection(&SrcRegion, ScreenBuffer, ScrollRectangle))
1987 {
1988 UNLOCK;
1989 return (Reply->Status = STATUS_INVALID_PARAMETER);
1990 }
1991
1992 if (UseClipRectangle)
1993 {
1994 if (!CsrpGetIntersection(&SrcRegion, SrcRegion, ClipRectangle))
1995 {
1996 UNLOCK;
1997 return (Reply->Status = STATUS_SUCCESS);
1998 }
1999 }
2000
2001
2002 CsrpInitRect(
2003 DstRegion,
2004 DestinationOrigin.Y,
2005 DestinationOrigin.X,
2006 DestinationOrigin.Y + CsrpRectHeight(ScrollRectangle) - 1,
2007 DestinationOrigin.X + CsrpRectWidth(ScrollRectangle) - 1)
2008
2009 /* Make sure destination rectangle is inside the screen buffer */
2010 if (!CsrpGetIntersection(&DstRegion, DstRegion, ScreenBuffer))
2011 {
2012 UNLOCK;
2013 return (Reply->Status = STATUS_INVALID_PARAMETER);
2014 }
2015
2016 CsrpCopyRegion(Buff, SrcRegion, DstRegion);
2017
2018
2019 /* Get the region that should be filled with the specified character and attributes */
2020
2021 DoFill = FALSE;
2022
2023 CsrpGetUnion(&FillRegion, SrcRegion, DstRegion);
2024
2025 if (CsrpSubtractRect(&FillRegion, FillRegion, DstRegion))
2026 {
2027 /* FIXME: The subtracted rectangle is off by one line */
2028 FillRegion.Top += 1;
2029
2030 CsrpFillRegion(Buff, FillRegion, Fill);
2031 DoFill = TRUE;
2032 }
2033
2034 if (Buff == ActiveConsole->ActiveBuffer)
2035 {
2036 /* Draw destination region */
2037 CsrpDrawRegion(ActiveConsole->ActiveBuffer, DstRegion);
2038
2039 if (DoFill)
2040 {
2041 /* Draw filled region */
2042 CsrpDrawRegion(ActiveConsole->ActiveBuffer, FillRegion);
2043 }
2044 }
2045
2046 UNLOCK;
2047 return(Reply->Status = STATUS_SUCCESS);
2048 }
2049
2050
2051 CSR_API(CsrReadConsoleOutputChar)
2052 {
2053 NTSTATUS Status;
2054 PCSRSS_SCREEN_BUFFER ScreenBuffer;
2055 DWORD Xpos, Ypos;
2056 BYTE* ReadBuffer;
2057 DWORD i;
2058
2059 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2060 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2061 ReadBuffer = Reply->Data.ReadConsoleOutputCharReply.String;
2062
2063 LOCK;
2064
2065 Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2066 if (!NT_SUCCESS(Status))
2067 {
2068 Reply->Status = Status;
2069 UNLOCK;
2070 return(Reply->Status);
2071 }
2072
2073 if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2074 {
2075 Reply->Status = STATUS_INVALID_HANDLE;
2076 UNLOCK;
2077 return(Reply->Status);
2078 }
2079
2080 Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X + ScreenBuffer->ShowX;
2081 Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
2082
2083 for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
2084 {
2085 *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX)];
2086
2087 ReadBuffer++;
2088 Xpos++;
2089
2090 if (Xpos == ScreenBuffer->MaxX)
2091 {
2092 Xpos = 0;
2093 Ypos++;
2094
2095 if (Ypos == ScreenBuffer->MaxY)
2096 Ypos = 0;
2097 }
2098 }
2099
2100 *ReadBuffer = 0;
2101
2102 Reply->Status = STATUS_SUCCESS;
2103 Reply->Data.ReadConsoleOutputCharReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
2104 Reply->Data.ReadConsoleOutputCharReply.EndCoord.Y = (Ypos - ScreenBuffer->ShowY + ScreenBuffer->MaxY) % ScreenBuffer->MaxY;
2105 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2106 Reply->Header.DataSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2107
2108 UNLOCK;
2109
2110 return(Reply->Status);
2111 }
2112
2113
2114 CSR_API(CsrReadConsoleOutputAttrib)
2115 {
2116 NTSTATUS Status;
2117 PCSRSS_SCREEN_BUFFER ScreenBuffer;
2118 DWORD Xpos, Ypos;
2119 CHAR* ReadBuffer;
2120 DWORD i;
2121
2122 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2123 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2124 ReadBuffer = Reply->Data.ReadConsoleOutputAttribReply.String;
2125
2126 LOCK;
2127
2128 Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2129 if (!NT_SUCCESS(Status))
2130 {
2131 Reply->Status = Status;
2132 UNLOCK;
2133 return(Reply->Status);
2134 }
2135
2136 if (ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2137 {
2138 Reply->Status = STATUS_INVALID_HANDLE;
2139 UNLOCK;
2140 return(Reply->Status);
2141 }
2142
2143 Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X + ScreenBuffer->ShowX;
2144 Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
2145
2146 for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2147 {
2148 *ReadBuffer = ScreenBuffer->Buffer[(Xpos * 2) + (Ypos * 2 * ScreenBuffer->MaxX) + 1];
2149
2150 ReadBuffer++;
2151 Xpos++;
2152
2153 if (Xpos == ScreenBuffer->MaxX)
2154 {
2155 Xpos = 0;
2156 Ypos++;
2157
2158 if (Ypos == ScreenBuffer->MaxY)
2159 Ypos = 0;
2160 }
2161 }
2162
2163 *ReadBuffer = 0;
2164
2165 Reply->Status = STATUS_SUCCESS;
2166 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.X = Xpos - ScreenBuffer->ShowX;
2167 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.Y = (Ypos - ScreenBuffer->ShowY + ScreenBuffer->MaxY) % ScreenBuffer->MaxY;
2168 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2169 Reply->Header.DataSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2170
2171 UNLOCK;
2172
2173 return(Reply->Status);
2174 }
2175
2176
2177 CSR_API(CsrGetNumberOfConsoleInputEvents)
2178 {
2179 NTSTATUS Status;
2180 PCSRSS_CONSOLE Console;
2181 PLIST_ENTRY CurrentItem;
2182 DWORD NumEvents;
2183
2184 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2185 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2186
2187 LOCK;
2188
2189 Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2190 if (!NT_SUCCESS(Status))
2191 {
2192 Reply->Status = Status;
2193 UNLOCK;
2194 return(Reply->Status);
2195 }
2196
2197 if (Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2198 {
2199 Reply->Status = STATUS_INVALID_HANDLE;
2200 UNLOCK;
2201 return(Reply->Status);
2202 }
2203
2204 CurrentItem = &Console->InputEvents;
2205 NumEvents = 0;
2206
2207 // If there are any events ...
2208 if(CurrentItem->Flink != CurrentItem)
2209 {
2210 do
2211 {
2212 CurrentItem = CurrentItem->Flink;
2213 ++NumEvents;
2214 }while(CurrentItem != &Console->InputEvents);
2215 }
2216
2217 UNLOCK;
2218
2219 Reply->Status = STATUS_SUCCESS;
2220 Reply->Data.GetNumInputEventsReply.NumInputEvents = NumEvents;
2221
2222 return Reply->Status;
2223 }
2224
2225
2226 CSR_API(CsrPeekConsoleInput)
2227 {
2228 NTSTATUS Status;
2229 PCSRSS_CONSOLE Console;
2230 DWORD Size;
2231 DWORD Length;
2232 PLIST_ENTRY CurrentItem;
2233 PLIST_ENTRY NextItem;
2234 PINPUT_RECORD InputRecord;
2235 ConsoleInput* Item;
2236 UINT NumItems;
2237
2238 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2239 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2240
2241 LOCK;
2242
2243 Status = CsrGetObject(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, (Object_t**)&Console);
2244 if(!NT_SUCCESS(Status))
2245 {
2246 Reply->Status = Status;
2247 UNLOCK;
2248 return Reply->Status;
2249 }
2250
2251 if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2252 {
2253 Reply->Status = STATUS_INVALID_HANDLE;
2254 UNLOCK;
2255 return Reply->Status;
2256 }
2257
2258 InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2259 Length = Request->Data.PeekConsoleInputRequest.Length;
2260 Size = Length * sizeof(INPUT_RECORD);
2261
2262 if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2263 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2264 {
2265 UNLOCK;
2266 Reply->Status = STATUS_ACCESS_VIOLATION;
2267 return Reply->Status ;
2268 }
2269
2270 NumItems = 0;
2271
2272 if(!IsListEmpty(&Console->InputEvents))
2273 {
2274 CurrentItem = &Console->InputEvents;
2275
2276 while(NumItems < Length)
2277 {
2278 ++NumItems;
2279 Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2280 *InputRecord++ = Item->InputEvent;
2281
2282 if(CurrentItem->Flink == &Console->InputEvents)
2283 break;
2284 else
2285 CurrentItem = CurrentItem->Flink;
2286 }
2287 }
2288
2289 UNLOCK;
2290
2291 Reply->Status = STATUS_SUCCESS;
2292 Reply->Data.PeekConsoleInputReply.Length = NumItems;
2293 return Reply->Status;
2294 }
2295
2296
2297 CSR_API(CsrReadConsoleOutput)
2298 {
2299 PCHAR_INFO CharInfo;
2300 PCHAR_INFO CurCharInfo;
2301 PCSRSS_SCREEN_BUFFER ScreenBuffer;
2302 DWORD Size;
2303 DWORD Length;
2304 DWORD SizeX, SizeY;
2305 NTSTATUS Status;
2306 COORD BufferSize;
2307 COORD BufferCoord;
2308 SMALL_RECT ReadRegion;
2309 SMALL_RECT ScreenRect;
2310 DWORD i, Y, X, Offset;
2311
2312 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2313 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2314
2315 LOCK;
2316
2317 Status = CsrGetObject(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, (Object_t**)&ScreenBuffer);
2318 if(!NT_SUCCESS(Status))
2319 {
2320 Reply->Status = Status;
2321 UNLOCK;
2322 return Reply->Status;
2323 }
2324
2325 if(ScreenBuffer->Header.Type != CSRSS_SCREEN_BUFFER_MAGIC)
2326 {
2327 Reply->Status = STATUS_INVALID_HANDLE;
2328 UNLOCK;
2329 return Reply->Status;
2330 }
2331
2332 CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
2333 ReadRegion = Request->Data.ReadConsoleOutputRequest.ReadRegion;
2334 BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
2335 BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
2336 Length = BufferSize.X * BufferSize.Y;
2337 Size = Length * sizeof(INPUT_RECORD);
2338
2339 if(((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
2340 || (((PVOID)CharInfo + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2341 {
2342 UNLOCK;
2343 Reply->Status = STATUS_ACCESS_VIOLATION;
2344 return Reply->Status ;
2345 }
2346
2347 SizeY = RtlMin(BufferSize.Y - BufferCoord.Y, CsrpRectHeight(ReadRegion));
2348 SizeX = RtlMin(BufferSize.X - BufferCoord.X, CsrpRectWidth(ReadRegion));
2349 ReadRegion.Bottom = ReadRegion.Top + SizeY;
2350 ReadRegion.Right = ReadRegion.Left + SizeX;
2351
2352 CsrpInitRect(ScreenRect, 0, 0, ScreenBuffer->MaxY - 1, ScreenBuffer->MaxX - 1);
2353 if (!CsrpGetIntersection(&ReadRegion, ScreenRect, ReadRegion))
2354 {
2355 UNLOCK;
2356 Reply->Status = STATUS_SUCCESS;
2357 return Reply->Status;
2358 }
2359
2360 for(i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
2361 {
2362 CurCharInfo = CharInfo + (i * BufferSize.Y);
2363
2364 Offset = (((Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY) * ScreenBuffer->MaxX + ReadRegion.Left) * 2;
2365 for(X = ReadRegion.Left; X < ReadRegion.Right; ++X)
2366 {
2367 CurCharInfo->Char.AsciiChar = GET_CELL_BUFFER(ScreenBuffer, Offset);
2368 CurCharInfo->Attributes = GET_CELL_BUFFER(ScreenBuffer, Offset);
2369 ++CurCharInfo;
2370 }
2371 }
2372
2373 UNLOCK;
2374
2375 Reply->Status = STATUS_SUCCESS;
2376 Reply->Data.ReadConsoleOutputReply.ReadRegion.Right = ReadRegion.Left + SizeX - 1;
2377 Reply->Data.ReadConsoleOutputReply.ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
2378 Reply->Data.ReadConsoleOutputReply.ReadRegion.Left = ReadRegion.Left;
2379 Reply->Data.ReadConsoleOutputReply.ReadRegion.Top = ReadRegion.Top;
2380
2381 return Reply->Status;
2382 }
2383
2384
2385 CSR_API(CsrWriteConsoleInput)
2386 {
2387 PINPUT_RECORD InputRecord;
2388 PCSRSS_CONSOLE Console;
2389 NTSTATUS Status;
2390 DWORD Length;
2391 DWORD Size;
2392 DWORD i;
2393 PLIST_ENTRY NextItem;
2394 ConsoleInput* Record;
2395
2396 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2397 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2398
2399 LOCK;
2400
2401 Status = CsrGetObject(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, (Object_t**)&Console);
2402 if(!NT_SUCCESS(Status))
2403 {
2404 Reply->Status = Status;
2405 UNLOCK;
2406 return Reply->Status;
2407 }
2408
2409 if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2410 {
2411 Reply->Status = STATUS_INVALID_HANDLE;
2412 UNLOCK;
2413 return Reply->Status;
2414 }
2415
2416 InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
2417 Length = Request->Data.WriteConsoleInputRequest.Length;
2418 Size = Length * sizeof(INPUT_RECORD);
2419
2420 if(((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2421 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2422 {
2423 UNLOCK;
2424 Reply->Status = STATUS_ACCESS_VIOLATION;
2425 return Reply->Status ;
2426 }
2427
2428 for(i = 0; i < Length; ++i)
2429 {
2430 Record = RtlAllocateHeap(CsrssApiHeap, 0, sizeof(ConsoleInput));
2431 if(Record == NULL)
2432 {
2433 UNLOCK;
2434 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
2435 return Reply->Status;
2436 }
2437
2438 Record->InputEvent = *InputRecord++;
2439 InsertTailList(&Console->InputEvents, &Record->ListEntry);
2440 }
2441
2442 UNLOCK;
2443
2444 Reply->Status = STATUS_SUCCESS;
2445 Reply->Data.WriteConsoleInputReply.Length = i;
2446 return Reply->Status;
2447 }
2448
2449 /**********************************************************************
2450 * HardwareStateProperty
2451 *
2452 * DESCRIPTION
2453 * Set/Get the value of the HardwareState and switch
2454 * between direct video buffer ouput and GDI windowed
2455 * output.
2456 * ARGUMENTS
2457 * Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
2458 * object. We use the same object to reply.
2459 * NOTE
2460 * ConsoleHwState has the correct size to be compatible
2461 * with NT's, but values are not.
2462 */
2463 static NTSTATUS FASTCALL SetConsoleHardwareState (PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
2464 {
2465 if ( (CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
2466 ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
2467 {
2468 if (Console->HardwareState != ConsoleHwState)
2469 {
2470 /* TODO: implement switching from full screen to windowed mode */
2471 /* TODO: or back; now simply store the hardware state */
2472 Console->HardwareState = ConsoleHwState;
2473 }
2474 return STATUS_SUCCESS;
2475 }
2476 return STATUS_INVALID_PARAMETER_3; // Client: (handle, set_get, [mode])
2477 }
2478
2479 CSR_API(CsrHardwareStateProperty)
2480 {
2481 PCSRSS_CONSOLE Console;
2482 NTSTATUS Status;
2483
2484 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2485 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2486
2487 LOCK;
2488
2489 Status = CsrGetObject (
2490 ProcessData,
2491 Request->Data.ConsoleHardwareStateRequest.ConsoleHandle,
2492 (Object_t**) & Console
2493 );
2494 if (!NT_SUCCESS(Status))
2495 {
2496 Reply->Status = Status;
2497 }
2498 else
2499 {
2500 if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2501 {
2502 Reply->Status = STATUS_INVALID_HANDLE;
2503 }
2504 else
2505 {
2506 switch (Request->Data.ConsoleHardwareStateRequest.SetGet)
2507 {
2508 case CONSOLE_HARDWARE_STATE_GET:
2509 Reply->Data.ConsoleHardwareStateReply.State = Console->HardwareState;
2510 break;
2511
2512 case CONSOLE_HARDWARE_STATE_SET:
2513 Reply->Status = SetConsoleHardwareState (Console, Request->Data.ConsoleHardwareStateRequest.State);
2514 break;
2515
2516 default:
2517 Reply->Status = STATUS_INVALID_PARAMETER_2; // Client: (handle, [set_get], mode)
2518 break;
2519 }
2520 }
2521 }
2522
2523 UNLOCK;
2524
2525 return Reply->Status;
2526 }
2527
2528 CSR_API(CsrGetConsoleWindow)
2529 {
2530 PCSRSS_CONSOLE Console;
2531 NTSTATUS Status;
2532
2533 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2534 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2535
2536 LOCK;
2537
2538 Status = CsrGetObject (
2539 ProcessData,
2540 Request->Data.ConsoleWindowRequest.ConsoleHandle,
2541 (Object_t**) & Console
2542 );
2543 if (!NT_SUCCESS(Status))
2544 {
2545 Reply->Status = Status;
2546 }
2547 else
2548 {
2549 if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
2550 {
2551 Reply->Status = STATUS_INVALID_HANDLE;
2552 }
2553 else
2554 {
2555 // Is this GDI handle valid in the client's context?
2556 Reply->Data.ConsoleWindowReply.WindowHandle = Console->hWindow;
2557 }
2558 }
2559
2560 UNLOCK;
2561
2562 return Reply->Status;
2563 }
2564
2565 /* EOF */