- Initialize/delete the lock of a console.
[reactos.git] / reactos / subsys / csrss / win32csr / conio.c
1 /* $Id: conio.c,v 1.7 2004/02/27 17:35:42 hbirr Exp $
2 *
3 * reactos/subsys/csrss/win32csr/conio.c
4 *
5 * Console I/O functions
6 *
7 * ReactOS Operating System
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <string.h>
13 #include <windows.h>
14
15 #include <csrss/csrss.h>
16 #include <ntdll/rtl.h>
17 #include <ntdll/ldr.h>
18 #include <ddk/ntddblue.h>
19 #include <rosrtl/string.h>
20 #include <rosrtl/minmax.h>
21 #include "api.h"
22 #include "conio.h"
23 #include "desktopbg.h"
24 #include "guiconsole.h"
25 #include "tuiconsole.h"
26 #include "win32csr.h"
27
28 #define NDEBUG
29 #include <debug.h>
30
31 /* FIXME: Is there a way to create real aliasses with gcc? [CSH] */
32 #define ALIAS(Name, Target) typeof(Target) Name = Target
33
34 /* Private user32 routines for CSRSS, not defined in any header file */
35 extern VOID STDCALL PrivateCsrssRegisterPrimitive(VOID);
36 extern VOID STDCALL PrivateCsrssAcquireOrReleaseInputOwnership(BOOL Release);
37
38 /* GLOBALS *******************************************************************/
39
40 #define ConioInitRect(Rect, Top, Left, Bottom, Right) \
41 ((Rect)->top) = Top; \
42 ((Rect)->left) = Left; \
43 ((Rect)->bottom) = Bottom; \
44 ((Rect)->right) = Right
45
46 #define ConioIsRectEmpty(Rect) \
47 (((Rect)->left > (Rect)->right) || ((Rect)->top > (Rect)->bottom))
48
49 /* FUNCTIONS *****************************************************************/
50
51 STATIC NTSTATUS FASTCALL
52 ConioConsoleFromProcessData(PCSRSS_PROCESS_DATA ProcessData, PCSRSS_CONSOLE *Console)
53 {
54 if (NULL == ProcessData->Console)
55 {
56 *Console = NULL;
57 return STATUS_SUCCESS;
58 }
59
60 EnterCriticalSection(&(ProcessData->Console->Header.Lock));
61 *Console = ProcessData->Console;
62
63 return STATUS_SUCCESS;
64 }
65
66 STATIC VOID FASTCALL
67 CsrConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData)
68 {
69 HANDLE Process, Thread;
70
71 DPRINT("CsrConsoleCtrlEvent Parent ProcessId = %x\n", ClientId.UniqueProcess);
72
73 if (ProcessData->CtrlDispatcher)
74 {
75 Process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, ProcessData->ProcessId);
76 if (NULL == Process)
77 {
78 DPRINT1("Failed for handle duplication\n");
79 return;
80 }
81
82 DPRINT("CsrConsoleCtrlEvent Process Handle = %x\n", Process);
83
84 Thread = CreateRemoteThread(Process, NULL, 0,
85 (LPTHREAD_START_ROUTINE) ProcessData->CtrlDispatcher,
86 (PVOID) Event, 0, NULL);
87 if (NULL == Thread)
88 {
89 DPRINT1("Failed thread creation\n");
90 CloseHandle(Process);
91 return;
92 }
93 CloseHandle(Thread);
94 CloseHandle(Process);
95 }
96 }
97
98 #define GET_CELL_BUFFER(b,o)\
99 (b)->Buffer[(o)++];
100
101 #define SET_CELL_BUFFER(b,o,c,a)\
102 (b)->Buffer[(o)++]=(c);\
103 (b)->Buffer[(o)++]=(a);
104
105 static VOID FASTCALL
106 ClearLineBuffer(PCSRSS_SCREEN_BUFFER Buff)
107 {
108 DWORD Offset = 2 * (Buff->CurrentY * Buff->MaxX);
109 UINT Pos;
110
111 for (Pos = 0; Pos < Buff->MaxX; Pos++)
112 {
113 /* Fill the cell: Offset is incremented by the macro */
114 SET_CELL_BUFFER(Buff, Offset, ' ', Buff->DefaultAttrib)
115 }
116 }
117
118 STATIC NTSTATUS FASTCALL
119 CsrInitConsoleScreenBuffer(PCSRSS_CONSOLE Console,
120 PCSRSS_SCREEN_BUFFER Buffer)
121 {
122 Buffer->Header.Type = CONIO_SCREEN_BUFFER_MAGIC;
123 Buffer->Header.ReferenceCount = 0;
124 Buffer->MaxX = Console->Size.X;
125 Buffer->MaxY = Console->Size.Y;
126 Buffer->ShowX = 0;
127 Buffer->ShowY = 0;
128 Buffer->Buffer = HeapAlloc(Win32CsrApiHeap, 0, Buffer->MaxX * Buffer->MaxY * 2);
129 if (NULL == Buffer->Buffer)
130 {
131 return STATUS_INSUFFICIENT_RESOURCES;
132 }
133 RtlInitializeCriticalSection(&Buffer->Header.Lock);
134 ConioInitScreenBuffer(Console, Buffer);
135 /* initialize buffer to be empty with default attributes */
136 for (Buffer->CurrentY = 0 ; Buffer->CurrentY < Buffer->MaxY; Buffer->CurrentY++)
137 {
138 ClearLineBuffer(Buffer);
139 }
140 Buffer->CursorInfo.bVisible = TRUE;
141 Buffer->CursorInfo.dwSize = 5;
142 Buffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
143 Buffer->CurrentX = 0;
144 Buffer->CurrentY = 0;
145
146 return STATUS_SUCCESS;
147 }
148
149 STATIC NTSTATUS STDCALL
150 CsrInitConsole(PCSRSS_CONSOLE Console)
151 {
152 NTSTATUS Status;
153 SECURITY_ATTRIBUTES SecurityAttributes;
154 PCSRSS_SCREEN_BUFFER NewBuffer;
155 BOOL GuiMode;
156
157 Console->Title.MaximumLength = Console->Title.Length = 0;
158 Console->Title.Buffer = NULL;
159
160 RtlCreateUnicodeString(&Console->Title, L"Command Prompt");
161
162 Console->Header.ReferenceCount = 0;
163 Console->WaitingChars = 0;
164 Console->WaitingLines = 0;
165 Console->EchoCount = 0;
166 Console->Header.Type = CONIO_CONSOLE_MAGIC;
167 Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
168 Console->EarlyReturn = FALSE;
169 Console->ActiveBuffer = NULL;
170 InitializeListHead(&Console->InputEvents);
171 InitializeListHead(&Console->ProcessList);
172
173 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
174 SecurityAttributes.lpSecurityDescriptor = NULL;
175 SecurityAttributes.bInheritHandle = TRUE;
176
177 Console->ActiveEvent = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
178 if (NULL == Console->ActiveEvent)
179 {
180 RtlFreeUnicodeString(&Console->Title);
181 return STATUS_UNSUCCESSFUL;
182 }
183 Console->PrivateData = NULL;
184 RtlInitializeCriticalSection(&Console->Header.Lock);
185 GuiMode = DtbgIsDesktopVisible();
186 if (! GuiMode)
187 {
188 Status = TuiInitConsole(Console);
189 if (! NT_SUCCESS(Status))
190 {
191 DPRINT1("Failed to open text-mode console, switching to gui-mode\n");
192 GuiMode = TRUE;
193 }
194 }
195 if (GuiMode)
196 {
197 Status = GuiInitConsole(Console);
198 if (! NT_SUCCESS(Status))
199 {
200 RtlFreeUnicodeString(&Console->Title);
201 RtlDeleteCriticalSection(&Console->Header.Lock);
202 CloseHandle(Console->ActiveEvent);
203 return Status;
204 }
205 }
206
207 NewBuffer = HeapAlloc(Win32CsrApiHeap, 0, sizeof(CSRSS_SCREEN_BUFFER));
208 if (NULL == NewBuffer)
209 {
210 RtlFreeUnicodeString(&Console->Title);
211 RtlDeleteCriticalSection(&Console->Header.Lock);
212 CloseHandle(Console->ActiveEvent);
213 return STATUS_INSUFFICIENT_RESOURCES;
214 }
215 Status = CsrInitConsoleScreenBuffer(Console, NewBuffer);
216 if (! NT_SUCCESS(Status))
217 {
218 RtlFreeUnicodeString(&Console->Title);
219 RtlDeleteCriticalSection(&Console->Header.Lock);
220 CloseHandle(Console->ActiveEvent);
221 HeapFree(Win32CsrApiHeap, 0, NewBuffer);
222 return Status;
223 }
224 Console->ActiveBuffer = NewBuffer;
225 /* add a reference count because the buffer is tied to the console */
226 Console->ActiveBuffer->Header.ReferenceCount++;
227 /* make console active, and insert into console list */
228 /* copy buffer contents to screen */
229 ConioDrawConsole(Console);
230
231 return STATUS_SUCCESS;
232 }
233
234
235 CSR_API(CsrAllocConsole)
236 {
237 PCSRSS_CONSOLE Console;
238 HANDLE Process;
239 NTSTATUS Status;
240
241 DPRINT("CsrAllocConsole\n");
242
243 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
244 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
245
246 if (ProcessData == NULL)
247 {
248 return Reply->Status = STATUS_INVALID_PARAMETER;
249 }
250
251 if (ProcessData->Console)
252 {
253 Reply->Status = STATUS_INVALID_PARAMETER;
254 return STATUS_INVALID_PARAMETER;
255 }
256
257 Reply->Status = STATUS_SUCCESS;
258 Console = HeapAlloc(Win32CsrApiHeap, 0, sizeof(CSRSS_CONSOLE));
259 if (NULL == Console)
260 {
261 Reply->Status = STATUS_NO_MEMORY;
262 return STATUS_NO_MEMORY;
263 }
264 Reply->Status = CsrInitConsole(Console);
265 if (! NT_SUCCESS(Reply->Status))
266 {
267 HeapFree(Win32CsrApiHeap, 0, Console);
268 return Reply->Status;
269 }
270 ProcessData->Console = Console;
271 Reply->Data.AllocConsoleReply.Console = Console;
272
273 /* add a reference count because the process is tied to the console */
274 Console->Header.ReferenceCount++;
275 Status = Win32CsrInsertObject(ProcessData, &Reply->Data.AllocConsoleReply.InputHandle, &Console->Header);
276 if (! NT_SUCCESS(Status))
277 {
278 ConioDeleteConsole((Object_t *) Console);
279 ProcessData->Console = 0;
280 return Reply->Status = Status;
281 }
282 Status = Win32CsrInsertObject(ProcessData, &Reply->Data.AllocConsoleReply.OutputHandle, &Console->ActiveBuffer->Header);
283 if (!NT_SUCCESS(Status))
284 {
285 Console->Header.ReferenceCount--;
286 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.InputHandle);
287 ProcessData->Console = 0;
288 return Reply->Status = Status;
289 }
290
291 Process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, ProcessData->ProcessId);
292 if (NULL == Process)
293 {
294 DPRINT1("OpenProcess() failed for handle duplication\n");
295 Console->Header.ReferenceCount--;
296 ProcessData->Console = 0;
297 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.OutputHandle);
298 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.InputHandle);
299 Reply->Status = Status;
300 return Status;
301 }
302 if (! DuplicateHandle(GetCurrentProcess(), ProcessData->Console->ActiveEvent,
303 Process, &ProcessData->ConsoleEvent, EVENT_ALL_ACCESS, FALSE, 0))
304 {
305 DPRINT1("DuplicateHandle() failed: %d\n", GetLastError);
306 CloseHandle(Process);
307 Console->Header.ReferenceCount--;
308 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.OutputHandle);
309 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.InputHandle);
310 ProcessData->Console = 0;
311 Reply->Status = Status;
312 return Status;
313 }
314 CloseHandle(Process);
315 ProcessData->CtrlDispatcher = Request->Data.AllocConsoleRequest.CtrlDispatcher;
316 DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
317 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ProcessEntry);
318
319 return STATUS_SUCCESS;
320 }
321
322 CSR_API(CsrFreeConsole)
323 {
324 PCSRSS_CONSOLE Console;
325
326 DPRINT("CsrFreeConsole\n");
327
328 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
329 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
330
331 if (ProcessData == NULL || ProcessData->Console == NULL)
332 {
333 return Reply->Status = STATUS_INVALID_PARAMETER;
334 }
335
336 Console = ProcessData->Console;
337 Console->Header.ReferenceCount--;
338 ProcessData->Console = NULL;
339 if (0 == Console->Header.ReferenceCount)
340 {
341 ConioDeleteConsole((Object_t *) Console);
342 }
343
344 return STATUS_SUCCESS;
345 }
346
347 STATIC VOID FASTCALL
348 ConioNextLine(PCSRSS_SCREEN_BUFFER Buff, RECT *UpdateRect, UINT *ScrolledLines)
349 {
350 /* slide the viewable screen */
351 if (((Buff->CurrentY - Buff->ShowY + Buff->MaxY) % Buff->MaxY) == Buff->MaxY - 1)
352 {
353 if (++Buff->ShowY == Buff->MaxY)
354 {
355 Buff->ShowY = 0;
356 }
357 (*ScrolledLines)++;
358 }
359 if (++Buff->CurrentY == Buff->MaxY)
360 {
361 Buff->CurrentY = 0;
362 }
363 ClearLineBuffer(Buff);
364 UpdateRect->left = 0;
365 UpdateRect->right = Buff->MaxX - 1;
366 if (UpdateRect->top == Buff->CurrentY)
367 {
368 if (++UpdateRect->top == Buff->MaxY)
369 {
370 UpdateRect->top = 0;
371 }
372 }
373 UpdateRect->bottom = Buff->CurrentY;
374 }
375
376 STATIC NTSTATUS FASTCALL
377 ConioWriteConsole(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff,
378 CHAR *Buffer, DWORD Length, BOOL Attrib)
379 {
380 int i;
381 DWORD Offset;
382 RECT UpdateRect;
383 LONG CursorStartX, CursorStartY;
384 UINT ScrolledLines;
385
386 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &CursorStartX, &CursorStartY);
387 UpdateRect.left = Buff->MaxX;
388 UpdateRect.top = Buff->CurrentY;
389 UpdateRect.right = -1;
390 UpdateRect.bottom = Buff->CurrentY;
391 ScrolledLines = 0;
392
393 for (i = 0; i < Length; i++)
394 {
395 switch(Buffer[i])
396 {
397 /* --- LF --- */
398 case '\n':
399 Buff->CurrentX = 0;
400 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
401 break;
402
403 /* --- BS --- */
404 case '\b':
405 /* Only handle BS if we're not on the first pos of the first line */
406 if (0 != Buff->CurrentX || Buff->ShowY != Buff->CurrentY)
407 {
408 if (0 == Buff->CurrentX)
409 {
410 /* slide virtual position up */
411 Buff->CurrentX = Buff->MaxX - 1;
412 if (0 == Buff->CurrentY)
413 {
414 Buff->CurrentY = Buff->MaxY;
415 }
416 else
417 {
418 Buff->CurrentY--;
419 }
420 if ((0 == UpdateRect.top && UpdateRect.bottom < Buff->CurrentY)
421 || (0 != UpdateRect.top && Buff->CurrentY < UpdateRect.top))
422 {
423 UpdateRect.top = Buff->CurrentY;
424 }
425 }
426 else
427 {
428 Buff->CurrentX--;
429 }
430 Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + Buff->CurrentX);
431 SET_CELL_BUFFER(Buff, Offset, ' ', Buff->DefaultAttrib);
432 UpdateRect.left = RtlRosMin(UpdateRect.left, Buff->CurrentX);
433 UpdateRect.right = RtlRosMax(UpdateRect.right, (LONG) Buff->CurrentX);
434 }
435 break;
436
437 /* --- CR --- */
438 case '\r':
439 Buff->CurrentX = 0;
440 UpdateRect.left = RtlRosMin(UpdateRect.left, Buff->CurrentX);
441 UpdateRect.right = RtlRosMax(UpdateRect.right, (LONG) Buff->CurrentX);
442 break;
443
444 /* --- TAB --- */
445 case '\t':
446 {
447 UINT EndX;
448
449 UpdateRect.left = RtlRosMin(UpdateRect.left, Buff->CurrentX);
450 EndX = 8 * ((Buff->CurrentX + 8) / 8);
451 if (Buff->MaxX < EndX)
452 {
453 EndX = Buff->MaxX;
454 }
455 Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
456 while (Buff->CurrentX < EndX)
457 {
458 Buff->Buffer[Offset] = ' ';
459 Offset += 2;
460 Buff->CurrentX++;
461 }
462 UpdateRect.right = RtlRosMax(UpdateRect.right, (LONG) Buff->CurrentX - 1);
463 if (Buff->CurrentX == Buff->MaxX)
464 {
465 Buff->CurrentX = 0;
466 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
467 }
468 }
469 break;
470
471 /* --- */
472 default:
473 UpdateRect.left = RtlRosMin(UpdateRect.left, Buff->CurrentX);
474 UpdateRect.right = RtlRosMax(UpdateRect.right, (LONG) Buff->CurrentX);
475 Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
476 Buff->Buffer[Offset++] = Buffer[i];
477 if (Attrib)
478 {
479 Buff->Buffer[Offset] = Buff->DefaultAttrib;
480 }
481 Buff->CurrentX++;
482 if (Buff->CurrentX == Buff->MaxX)
483 {
484 Buff->CurrentX = 0;
485 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
486 }
487 break;
488 }
489 }
490
491 ConioPhysicalToLogical(Buff, UpdateRect.left, UpdateRect.top, &(UpdateRect.left),
492 &(UpdateRect.top));
493 ConioPhysicalToLogical(Buff, UpdateRect.right, UpdateRect.bottom, &(UpdateRect.right),
494 &(UpdateRect.bottom));
495 if (! ConioIsRectEmpty(&UpdateRect) && NULL != Console && Buff == Console->ActiveBuffer)
496 {
497 ConioWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY, ScrolledLines,
498 Buffer, Length);
499 }
500
501 return STATUS_SUCCESS;
502 }
503
504 CSR_API(CsrReadConsole)
505 {
506 PLIST_ENTRY CurrentEntry;
507 ConsoleInput *Input;
508 PCHAR Buffer;
509 int i;
510 ULONG nNumberOfCharsToRead;
511 PCSRSS_CONSOLE Console;
512 NTSTATUS Status;
513
514 DPRINT("CsrReadConsole\n");
515
516 /* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
517 nNumberOfCharsToRead = Request->Data.ReadConsoleRequest.NrCharactersToRead > CSRSS_MAX_READ_CONSOLE_REQUEST ? CSRSS_MAX_READ_CONSOLE_REQUEST : Request->Data.ReadConsoleRequest.NrCharactersToRead;
518 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
519 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
520
521 Buffer = Reply->Data.ReadConsoleReply.Buffer;
522 Status = ConioLockConsole(ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle,
523 &Console);
524 if (! NT_SUCCESS(Status))
525 {
526 return Reply->Status = Status;
527 }
528 Reply->Data.ReadConsoleReply.EventHandle = ProcessData->ConsoleEvent;
529 for (i = 0; i < nNumberOfCharsToRead && Console->InputEvents.Flink != &Console->InputEvents; i++)
530 {
531 /* remove input event from queue */
532 CurrentEntry = RemoveHeadList(&Console->InputEvents);
533 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
534
535 /* only pay attention to valid ascii chars, on key down */
536 if (KEY_EVENT == Input->InputEvent.EventType
537 && Input->InputEvent.Event.KeyEvent.bKeyDown
538 && Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
539 {
540 /* backspace handling */
541 if ('\b' == Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
542 {
543 /* echo if it has not already been done, and either we or the client has chars to be deleted */
544 if (! Input->Echoed
545 && (0 != i || Request->Data.ReadConsoleRequest.nCharsCanBeDeleted))
546 {
547 ConioWriteConsole(Console, Console->ActiveBuffer,
548 &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE);
549 }
550 if (0 != i)
551 {
552 i -= 2; /* if we already have something to return, just back it up by 2 */
553 }
554 else
555 { /* otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer */
556 Reply->Data.ReadConsoleReply.NrCharactersRead = 0;
557 Reply->Status = STATUS_NOTIFY_CLEANUP;
558 Console->WaitingChars--;
559 HeapFree(Win32CsrApiHeap, 0, Input);
560 ConioUnlockConsole(Console);
561 return STATUS_NOTIFY_CLEANUP;
562 }
563 Request->Data.ReadConsoleRequest.nCharsCanBeDeleted--;
564 Input->Echoed = TRUE; /* mark as echoed so we don't echo it below */
565 }
566 /* do not copy backspace to buffer */
567 else
568 {
569 Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar;
570 }
571 /* echo to screen if enabled and we did not already echo the char */
572 if (0 != (Console->Mode & ENABLE_ECHO_INPUT)
573 && ! Input->Echoed
574 && '\r' != Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
575 {
576 ConioWriteConsole(Console, Console->ActiveBuffer,
577 &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE);
578 }
579 }
580 else
581 {
582 i--;
583 }
584 Console->WaitingChars--;
585 HeapFree(Win32CsrApiHeap, 0, Input);
586 }
587 Reply->Data.ReadConsoleReply.NrCharactersRead = i;
588 if (0 == i)
589 {
590 Reply->Status = STATUS_PENDING; /* we didn't read anything */
591 }
592 else if (0 != (Console->Mode & ENABLE_LINE_INPUT))
593 {
594 if (0 == Console->WaitingLines || '\n' != Buffer[i - 1])
595 {
596 Reply->Status = STATUS_PENDING; /* line buffered, didn't get a complete line */
597 }
598 else
599 {
600 Console->WaitingLines--;
601 Reply->Status = STATUS_SUCCESS; /* line buffered, did get a complete line */
602 }
603 }
604 else
605 {
606 Reply->Status = STATUS_SUCCESS; /* not line buffered, did read something */
607 }
608
609 if (Reply->Status == STATUS_PENDING)
610 {
611 Console->EchoCount = nNumberOfCharsToRead - i;
612 }
613 else
614 {
615 Console->EchoCount = 0; /* if the client is no longer waiting on input, do not echo */
616 }
617 Reply->Header.MessageSize += i;
618
619 ConioUnlockConsole(Console);
620 return Reply->Status;
621 }
622
623 VOID FASTCALL
624 ConioPhysicalToLogical(PCSRSS_SCREEN_BUFFER Buff,
625 ULONG PhysicalX,
626 ULONG PhysicalY,
627 LONG *LogicalX,
628 LONG *LogicalY)
629 {
630 *LogicalX = PhysicalX;
631 if (PhysicalY < Buff->ShowY)
632 {
633 *LogicalY = Buff->MaxY - Buff->ShowY + PhysicalY;
634 }
635 else
636 {
637 *LogicalY = PhysicalY - Buff->ShowY;
638 }
639 }
640
641 inline BOOLEAN ConioIsEqualRect(
642 RECT *Rect1,
643 RECT *Rect2)
644 {
645 return ((Rect1->left == Rect2->left) && (Rect1->right == Rect2->right) &&
646 (Rect1->top == Rect2->top) && (Rect1->bottom == Rect2->bottom));
647 }
648
649 inline BOOLEAN ConioGetIntersection(
650 RECT *Intersection,
651 RECT *Rect1,
652 RECT *Rect2)
653 {
654 if (ConioIsRectEmpty(Rect1) ||
655 (ConioIsRectEmpty(Rect2)) ||
656 (Rect1->top > Rect2->bottom) ||
657 (Rect1->left > Rect2->right) ||
658 (Rect1->bottom < Rect2->top) ||
659 (Rect1->right < Rect2->left))
660 {
661 /* The rectangles do not intersect */
662 ConioInitRect(Intersection, 0, -1, 0, -1);
663 return FALSE;
664 }
665
666 ConioInitRect(Intersection,
667 RtlRosMax(Rect1->top, Rect2->top),
668 RtlRosMax(Rect1->left, Rect2->left),
669 RtlRosMin(Rect1->bottom, Rect2->bottom),
670 RtlRosMin(Rect1->right, Rect2->right));
671
672 return TRUE;
673 }
674
675 inline BOOLEAN ConioGetUnion(
676 RECT *Union,
677 RECT *Rect1,
678 RECT *Rect2)
679 {
680 if (ConioIsRectEmpty(Rect1))
681 {
682 if (ConioIsRectEmpty(Rect2))
683 {
684 ConioInitRect(Union, 0, -1, 0, -1);
685 return FALSE;
686 }
687 else
688 {
689 *Union = *Rect2;
690 }
691 }
692 else if (ConioIsRectEmpty(Rect2))
693 {
694 *Union = *Rect1;
695 }
696 else
697 {
698 ConioInitRect(Union,
699 RtlRosMin(Rect1->top, Rect2->top),
700 RtlRosMin(Rect1->left, Rect2->left),
701 RtlRosMax(Rect1->bottom, Rect2->bottom),
702 RtlRosMax(Rect1->right, Rect2->right));
703 }
704
705 return TRUE;
706 }
707
708 inline BOOLEAN ConioSubtractRect(
709 RECT *Subtraction,
710 RECT *Rect1,
711 RECT *Rect2)
712 {
713 RECT tmp;
714
715 if (ConioIsRectEmpty(Rect1))
716 {
717 ConioInitRect(Subtraction, 0, -1, 0, -1);
718 return FALSE;
719 }
720 *Subtraction = *Rect1;
721 if (ConioGetIntersection(&tmp, Rect1, Rect2))
722 {
723 if (ConioIsEqualRect(&tmp, Subtraction))
724 {
725 ConioInitRect(Subtraction, 0, -1, 0, -1);
726 return FALSE;
727 }
728 if ((tmp.top == Subtraction->top) && (tmp.bottom == Subtraction->bottom))
729 {
730 if (tmp.left == Subtraction->left)
731 {
732 Subtraction->left = tmp.right;
733 }
734 else if (tmp.right == Subtraction->right)
735 {
736 Subtraction->right = tmp.left;
737 }
738 }
739 else if ((tmp.left == Subtraction->left) && (tmp.right == Subtraction->right))
740 {
741 if (tmp.top == Subtraction->top)
742 {
743 Subtraction->top = tmp.bottom;
744 }
745 else if (tmp.bottom == Subtraction->bottom)
746 {
747 Subtraction->bottom = tmp.top;
748 }
749 }
750 }
751
752 return TRUE;
753 }
754
755 STATIC VOID FASTCALL
756 ConioCopyRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer,
757 RECT *SrcRegion,
758 RECT *DstRegion)
759 {
760 SHORT SrcY, DstY;
761 DWORD SrcOffset;
762 DWORD DstOffset;
763 DWORD BytesPerLine;
764 ULONG i;
765
766 DstY = DstRegion->top;
767 BytesPerLine = ConioRectWidth(DstRegion) * 2;
768
769 SrcY = (SrcRegion->top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
770 DstY = (DstRegion->top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
771 SrcOffset = (SrcY * ScreenBuffer->MaxX + SrcRegion->left + ScreenBuffer->ShowX) * 2;
772 DstOffset = (DstY * ScreenBuffer->MaxX + DstRegion->left + ScreenBuffer->ShowX) * 2;
773
774 for (i = SrcRegion->top; i <= SrcRegion->bottom; i++)
775 {
776 RtlCopyMemory(
777 &ScreenBuffer->Buffer[DstOffset],
778 &ScreenBuffer->Buffer[SrcOffset],
779 BytesPerLine);
780
781 if (++DstY == ScreenBuffer->MaxY)
782 {
783 DstY = 0;
784 DstOffset = (DstRegion->left + ScreenBuffer->ShowX) * 2;
785 }
786 else
787 {
788 DstOffset += ScreenBuffer->MaxX * 2;
789 }
790
791 if (++SrcY == ScreenBuffer->MaxY)
792 {
793 SrcY = 0;
794 SrcOffset = (SrcRegion->left + ScreenBuffer->ShowX) * 2;
795 }
796 else
797 {
798 SrcOffset += ScreenBuffer->MaxX * 2;
799 }
800 }
801 }
802
803 STATIC VOID FASTCALL
804 ConioFillRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer,
805 RECT *Region,
806 CHAR_INFO CharInfo)
807 {
808 SHORT X, Y;
809 DWORD Offset;
810 DWORD Delta;
811 ULONG i;
812
813 Y = (Region->top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
814 Offset = (Y * ScreenBuffer->MaxX + Region->left + ScreenBuffer->ShowX) * 2;
815 Delta = (ScreenBuffer->MaxX - ConioRectWidth(Region)) * 2;
816
817 for (i = Region->top; i <= Region->bottom; i++)
818 {
819 for (X = Region->left; X <= Region->right; X++)
820 {
821 SET_CELL_BUFFER(ScreenBuffer, Offset, CharInfo.Char.AsciiChar, CharInfo.Attributes);
822 }
823 if (++Y == ScreenBuffer->MaxY)
824 {
825 Y = 0;
826 Offset = (Region->left + ScreenBuffer->ShowX) * 2;
827 }
828 else
829 {
830 Offset += Delta;
831 }
832 }
833 }
834
835 CSR_API(CsrWriteConsole)
836 {
837 NTSTATUS Status;
838 BYTE *Buffer = Request->Data.WriteConsoleRequest.Buffer;
839 PCSRSS_SCREEN_BUFFER Buff;
840 PCSRSS_CONSOLE Console;
841
842 DPRINT("CsrWriteConsole\n");
843
844 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
845 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
846 sizeof(LPC_MESSAGE);
847
848 if (Request->Header.DataSize
849 < sizeof(CSRSS_WRITE_CONSOLE_REQUEST) - 1
850 + Request->Data.WriteConsoleRequest.NrCharactersToWrite)
851 {
852 DPRINT1("Invalid request size\n");
853 return Reply->Status = STATUS_INVALID_PARAMETER;
854 }
855 Status = ConioConsoleFromProcessData(ProcessData, &Console);
856 if (! NT_SUCCESS(Status))
857 {
858 return Reply->Status = Status;
859 }
860
861 Status = ConioLockScreenBuffer(ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle, &Buff);
862 if (! NT_SUCCESS(Status))
863 {
864 if (NULL != Console)
865 {
866 ConioUnlockConsole(Console);
867 }
868 return Reply->Status = Status;
869 }
870
871 ConioWriteConsole(Console, Buff, Buffer,
872 Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE);
873 ConioUnlockScreenBuffer(Buff);
874 if (NULL != Console)
875 {
876 ConioUnlockConsole(Console);
877 }
878
879 return Reply->Status = STATUS_SUCCESS;
880 }
881
882 VOID STDCALL
883 ConioDeleteScreenBuffer(Object_t *Object)
884 {
885 PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER) Object;
886 RtlDeleteCriticalSection(&Buffer->Header.Lock);
887 HeapFree(Win32CsrApiHeap, 0, Buffer->Buffer);
888 HeapFree(Win32CsrApiHeap, 0, Buffer);
889 }
890
891 VOID FASTCALL
892 ConioDrawConsole(PCSRSS_CONSOLE Console)
893 {
894 RECT Region;
895
896 ConioInitRect(&Region, 0, 0, Console->Size.Y - 1, Console->Size.X - 1);
897
898 ConioDrawRegion(Console, &Region);
899 }
900
901
902 VOID STDCALL
903 ConioDeleteConsole(Object_t *Object)
904 {
905 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Object;
906 ConsoleInput *Event;
907
908 DPRINT("ConioDeleteConsole\n");
909
910 /* Drain input event queue */
911 while (Console->InputEvents.Flink != &Console->InputEvents)
912 {
913 Event = (ConsoleInput *) Console->InputEvents.Flink;
914 Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
915 Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
916 HeapFree(Win32CsrApiHeap, 0, Event);
917 }
918
919 if (0 == --Console->ActiveBuffer->Header.ReferenceCount)
920 {
921 ConioDeleteScreenBuffer((Object_t *) Console->ActiveBuffer);
922 }
923
924 Console->ActiveBuffer = NULL;
925 ConioCleanupConsole(Console);
926
927 CloseHandle(Console->ActiveEvent);
928 RtlDeleteCriticalSection(&Console->Header.Lock);
929 RtlFreeUnicodeString(&Console->Title);
930 HeapFree(Win32CsrApiHeap, 0, Console);
931 }
932
933 VOID STDCALL
934 CsrInitConsoleSupport(VOID)
935 {
936 DPRINT("CSR: CsrInitConsoleSupport()\n");
937
938 /* Should call LoadKeyboardLayout */
939 }
940
941 STATIC VOID FASTCALL
942 ConioProcessChar(PCSRSS_CONSOLE Console,
943 ConsoleInput *KeyEventRecord)
944 {
945 BOOL updown;
946 BOOL bClientWake = FALSE;
947 ConsoleInput *TempInput;
948
949 /* process Ctrl-C and Ctrl-Break */
950 if (Console->Mode & ENABLE_PROCESSED_INPUT &&
951 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown &&
952 ((KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||
953 (KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
954 (KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)))
955 {
956 PCSRSS_PROCESS_DATA current;
957 PLIST_ENTRY current_entry;
958 DPRINT1("Console_Api Ctrl-C\n");
959 current_entry = Console->ProcessList.Flink;
960 while (current_entry != &Console->ProcessList)
961 {
962 current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
963 current_entry = current_entry->Flink;
964 CsrConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current);
965 }
966 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
967 return;
968 }
969
970 if (0 != (KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState
971 & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
972 && (VK_UP == KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode
973 || VK_DOWN == KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode))
974 {
975 if (KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown)
976 {
977 /* scroll up or down */
978 if (NULL == Console)
979 {
980 DPRINT1("No Active Console!\n");
981 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
982 return;
983 }
984 if (VK_UP == KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode)
985 {
986 /* only scroll up if there is room to scroll up into */
987 if (Console->ActiveBuffer->ShowY != ((Console->ActiveBuffer->CurrentY + 1) %
988 Console->ActiveBuffer->MaxY))
989 {
990 Console->ActiveBuffer->ShowY = (Console->ActiveBuffer->ShowY +
991 Console->ActiveBuffer->MaxY - 1) %
992 Console->ActiveBuffer->MaxY;
993 }
994 }
995 else if (Console->ActiveBuffer->ShowY != Console->ActiveBuffer->CurrentY)
996 /* only scroll down if there is room to scroll down into */
997 {
998 if (Console->ActiveBuffer->ShowY % Console->ActiveBuffer->MaxY !=
999 Console->ActiveBuffer->CurrentY)
1000 {
1001 if (((Console->ActiveBuffer->CurrentY + 1) % Console->ActiveBuffer->MaxY) !=
1002 (Console->ActiveBuffer->ShowY + Console->ActiveBuffer->MaxY) %
1003 Console->ActiveBuffer->MaxY)
1004 {
1005 Console->ActiveBuffer->ShowY = (Console->ActiveBuffer->ShowY + 1) %
1006 Console->ActiveBuffer->MaxY;
1007 }
1008 }
1009 }
1010 ConioDrawConsole(Console);
1011 }
1012 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
1013 return;
1014 }
1015 if (NULL == Console)
1016 {
1017 DPRINT1("No Active Console!\n");
1018 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
1019 return;
1020 }
1021
1022 if (0 != (Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)))
1023 {
1024 switch(KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1025 {
1026 case '\r':
1027 /* first add the \r */
1028 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1029 updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
1030 KeyEventRecord->Echoed = FALSE;
1031 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
1032 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
1033 InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry);
1034 Console->WaitingChars++;
1035 KeyEventRecord = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
1036 if (NULL == KeyEventRecord)
1037 {
1038 DPRINT1("Failed to allocate KeyEventRecord\n");
1039 return;
1040 }
1041 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1042 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
1043 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
1044 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
1045 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
1046 KeyEventRecord->Fake = TRUE;
1047 break;
1048 }
1049 }
1050 /* add event to the queue */
1051 InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry);
1052 Console->WaitingChars++;
1053 /* if line input mode is enabled, only wake the client on enter key down */
1054 if (0 == (Console->Mode & ENABLE_LINE_INPUT)
1055 || Console->EarlyReturn
1056 || ('\n' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
1057 && ! KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown))
1058 {
1059 if ('\n' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1060 {
1061 Console->WaitingLines++;
1062 }
1063 bClientWake = TRUE;
1064 SetEvent(Console->ActiveEvent);
1065 }
1066 KeyEventRecord->Echoed = FALSE;
1067 if (0 != (Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT))
1068 && '\b' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
1069 && KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown)
1070 {
1071 /* walk the input queue looking for a char to backspace */
1072 for (TempInput = (ConsoleInput *) Console->InputEvents.Blink;
1073 TempInput != (ConsoleInput *) &Console->InputEvents
1074 && (KEY_EVENT == TempInput->InputEvent.EventType
1075 || ! TempInput->InputEvent.Event.KeyEvent.bKeyDown
1076 || '\b' == TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar);
1077 TempInput = (ConsoleInput *) TempInput->ListEntry.Blink)
1078 {
1079 /* NOP */;
1080 }
1081 /* if we found one, delete it, otherwise, wake the client */
1082 if (TempInput != (ConsoleInput *) &Console->InputEvents)
1083 {
1084 /* delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue */
1085 RemoveEntryList(&TempInput->ListEntry);
1086 if (TempInput->Echoed)
1087 {
1088 ConioWriteConsole(Console, Console->ActiveBuffer,
1089 &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar,
1090 1, TRUE);
1091 }
1092 HeapFree(Win32CsrApiHeap, 0, TempInput);
1093 RemoveEntryList(&KeyEventRecord->ListEntry);
1094 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
1095 Console->WaitingChars -= 2;
1096 }
1097 else
1098 {
1099 SetEvent(Console->ActiveEvent);
1100 }
1101 }
1102 else
1103 {
1104 /* echo chars if we are supposed to and client is waiting for some */
1105 if (0 != (Console->Mode & ENABLE_ECHO_INPUT) && Console->EchoCount
1106 && KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
1107 && KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown
1108 && '\r' != KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1109 {
1110 /* mark the char as already echoed */
1111 ConioWriteConsole(Console, Console->ActiveBuffer,
1112 &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar,
1113 1, TRUE);
1114 Console->EchoCount--;
1115 KeyEventRecord->Echoed = TRUE;
1116 }
1117 }
1118
1119 /* Console->WaitingChars++; */
1120 if (bClientWake || 0 == (Console->Mode & ENABLE_LINE_INPUT))
1121 {
1122 SetEvent(Console->ActiveEvent);
1123 }
1124 }
1125
1126 STATIC DWORD FASTCALL
1127 ConioGetShiftState(PBYTE KeyState)
1128 {
1129 int i;
1130 DWORD ssOut = 0;
1131
1132 for (i = 0; i < 0x100; i++)
1133 {
1134 if (0 != (KeyState[i] & 0x80))
1135 {
1136 UINT vk = MapVirtualKeyExW(i, 3, 0) & 0xff;
1137 switch(vk)
1138 {
1139 case VK_CAPITAL:
1140 ssOut |= CAPSLOCK_ON;
1141 break;
1142
1143 case VK_NUMLOCK:
1144 ssOut |= NUMLOCK_ON;
1145 break;
1146
1147 case VK_SCROLL:
1148 ssOut |= SCROLLLOCK_ON;
1149 break;
1150 }
1151 }
1152 }
1153
1154 if (KeyState[VK_LSHIFT] & 0x80 || KeyState[VK_RSHIFT] & 0x80)
1155 ssOut |= SHIFT_PRESSED;
1156
1157 if (KeyState[VK_LCONTROL] & 0x80)
1158 ssOut |= RIGHT_CTRL_PRESSED;
1159 else if (KeyState[VK_RCONTROL] & 0x80)
1160 ssOut |= LEFT_CTRL_PRESSED;
1161
1162 if (KeyState[VK_LMENU] & 0x80)
1163 ssOut |= RIGHT_ALT_PRESSED;
1164 else if (KeyState[VK_RMENU] & 0x80)
1165 ssOut |= LEFT_ALT_PRESSED;
1166
1167 return ssOut;
1168 }
1169
1170 VOID STDCALL
1171 ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode)
1172 {
1173 static BYTE KeyState[256] = { 0 };
1174 /* MSDN mentions that you should use the last virtual key code received
1175 * when putting a virtual key identity to a WM_CHAR message since multiple
1176 * or translated keys may be involved. */
1177 static UINT LastVirtualKey = 0;
1178 DWORD ShiftState;
1179 ConsoleInput *ConInRec;
1180 UINT RepeatCount;
1181 CHAR AsciiChar;
1182 WCHAR UnicodeChar;
1183 UINT VirtualKeyCode;
1184 UINT VirtualScanCode;
1185 BOOL Down = FALSE;
1186 INPUT_RECORD er;
1187 ULONG ResultSize = 0;
1188
1189 RepeatCount = 1;
1190 VirtualScanCode = (msg->lParam >> 16) & 0xff;
1191 Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
1192 msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
1193
1194 GetKeyboardState(KeyState);
1195 ShiftState = ConioGetShiftState(KeyState);
1196
1197 if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
1198 {
1199 VirtualKeyCode = LastVirtualKey;
1200 UnicodeChar = msg->wParam;
1201 }
1202 else
1203 {
1204 WCHAR Chars[2];
1205 INT RetChars = 0;
1206
1207 VirtualKeyCode = msg->wParam;
1208 RetChars = ToUnicodeEx(VirtualKeyCode,
1209 VirtualScanCode,
1210 KeyState,
1211 Chars,
1212 2,
1213 0,
1214 0);
1215 UnicodeChar = (1 == RetChars ? Chars[0] : 0);
1216 }
1217
1218 if (UnicodeChar)
1219 {
1220 RtlUnicodeToOemN(&AsciiChar,
1221 1,
1222 &ResultSize,
1223 &UnicodeChar,
1224 sizeof(WCHAR));
1225 }
1226 if (0 == ResultSize)
1227 {
1228 AsciiChar = 0;
1229 }
1230
1231 er.EventType = KEY_EVENT;
1232 er.Event.KeyEvent.bKeyDown = Down;
1233 er.Event.KeyEvent.wRepeatCount = RepeatCount;
1234 er.Event.KeyEvent.uChar.UnicodeChar = AsciiChar & 0xff;
1235 er.Event.KeyEvent.dwControlKeyState = ShiftState;
1236 er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode;
1237 er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode;
1238
1239 if (TextMode)
1240 {
1241 if (0 != (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
1242 && VK_TAB == VirtualKeyCode)
1243 {
1244 if (Down)
1245 {
1246 TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
1247 }
1248
1249 return;
1250 }
1251 else if (VK_MENU == VirtualKeyCode && ! Down)
1252 {
1253 if (TuiSwapConsole(0))
1254 {
1255 return;
1256 }
1257 }
1258 }
1259
1260 if (NULL == Console)
1261 {
1262 return;
1263 }
1264
1265 ConInRec = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
1266
1267 if (NULL == ConInRec)
1268 {
1269 return;
1270 }
1271
1272 ConInRec->InputEvent = er;
1273 ConInRec->Fake = AsciiChar &&
1274 (msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
1275 msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
1276 ConInRec->NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
1277 ConInRec->Echoed = FALSE;
1278 if (ConInRec->NotChar)
1279 LastVirtualKey = msg->wParam;
1280
1281 DPRINT ("csrss: %s %s %s %s %02x %02x '%c' %04x\n",
1282 Down ? "down" : "up ",
1283 (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
1284 "char" : "key ",
1285 ConInRec->Fake ? "fake" : "real",
1286 ConInRec->NotChar ? "notc" : "char",
1287 VirtualScanCode,
1288 VirtualKeyCode,
1289 (AsciiChar >= ' ') ? AsciiChar : '.',
1290 ShiftState);
1291
1292 if (! ConInRec->Fake || ! ConInRec->NotChar)
1293 {
1294 ConioProcessChar(Console, ConInRec);
1295 }
1296 else
1297 {
1298 HeapFree(Win32CsrApiHeap, 0, ConInRec);
1299 }
1300 }
1301
1302 VOID
1303 Console_Api(DWORD RefreshEvent)
1304 {
1305 /* keep reading events from the keyboard and stuffing them into the current
1306 console's input queue */
1307 MSG msg;
1308
1309 /* This call establishes our message queue */
1310 PeekMessageW(&msg, 0, 0, 0, PM_NOREMOVE);
1311 /* This call registers our message queue */
1312 PrivateCsrssRegisterPrimitive();
1313 /* This call turns on the input system in win32k */
1314 PrivateCsrssAcquireOrReleaseInputOwnership(FALSE);
1315
1316 while (TRUE)
1317 {
1318 GetMessageW(&msg, 0, 0, 0);
1319 TranslateMessage(&msg);
1320
1321 if (msg.message == WM_CHAR || msg.message == WM_SYSCHAR ||
1322 msg.message == WM_KEYDOWN || msg.message == WM_KEYUP ||
1323 msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP)
1324 {
1325 ConioProcessKey(&msg, TuiGetFocusConsole(), TRUE);
1326 }
1327 }
1328
1329 PrivateCsrssAcquireOrReleaseInputOwnership(TRUE);
1330 }
1331
1332 CSR_API(CsrGetScreenBufferInfo)
1333 {
1334 NTSTATUS Status;
1335 PCSRSS_SCREEN_BUFFER Buff;
1336 PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1337
1338 DPRINT("CsrGetScreenBufferInfo\n");
1339
1340 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1341 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1342
1343 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle, &Buff);
1344 if (! NT_SUCCESS(Status))
1345 {
1346 return Reply->Status = Status;
1347 }
1348 pInfo = &Reply->Data.ScreenBufferInfoReply.Info;
1349 pInfo->dwSize.X = Buff->MaxX;
1350 pInfo->dwSize.Y = Buff->MaxY;
1351 pInfo->dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1352 pInfo->dwCursorPosition.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1353 pInfo->wAttributes = Buff->DefaultAttrib;
1354 pInfo->srWindow.Left = 0;
1355 pInfo->srWindow.Right = Buff->MaxX - 1;
1356 pInfo->srWindow.Top = 0;
1357 pInfo->srWindow.Bottom = Buff->MaxY - 1;
1358 pInfo->dwMaximumWindowSize.X = Buff->MaxX;
1359 pInfo->dwMaximumWindowSize.Y = Buff->MaxY;
1360 ConioUnlockScreenBuffer(Buff);
1361
1362 Reply->Status = STATUS_SUCCESS;
1363
1364 return Reply->Status;
1365 }
1366
1367 CSR_API(CsrSetCursor)
1368 {
1369 NTSTATUS Status;
1370 PCSRSS_CONSOLE Console;
1371 PCSRSS_SCREEN_BUFFER Buff;
1372 LONG OldCursorX, OldCursorY;
1373
1374 DPRINT("CsrSetCursor\n");
1375
1376 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1377 if (! NT_SUCCESS(Status))
1378 {
1379 return Reply->Status = Status;
1380 }
1381
1382 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1383 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1384
1385 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff);
1386 if (! NT_SUCCESS(Status))
1387 {
1388 if (NULL != Console)
1389 {
1390 ConioUnlockConsole(Console);
1391 }
1392 return Reply->Status = Status;
1393 }
1394
1395 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &OldCursorX, &OldCursorY);
1396 Buff->CurrentX = Request->Data.SetCursorRequest.Position.X + Buff->ShowX;
1397 Buff->CurrentY = (Request->Data.SetCursorRequest.Position.Y + Buff->ShowY) % Buff->MaxY;
1398 if (NULL != Console && Buff == Console->ActiveBuffer)
1399 {
1400 if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
1401 {
1402 ConioUnlockScreenBuffer(Buff);
1403 return Reply->Status = STATUS_UNSUCCESSFUL;
1404 }
1405 }
1406
1407 ConioUnlockScreenBuffer(Buff);
1408 if (NULL != Console)
1409 {
1410 ConioUnlockConsole(Console);
1411 }
1412
1413 return Reply->Status = STATUS_SUCCESS;
1414 }
1415
1416 STATIC FASTCALL VOID
1417 ConioComputeUpdateRect(PCSRSS_SCREEN_BUFFER Buff, RECT *UpdateRect, COORD *Start, UINT Length)
1418 {
1419 if (Buff->MaxX <= Start->X + Length)
1420 {
1421 UpdateRect->left = 0;
1422 }
1423 else
1424 {
1425 UpdateRect->left = Start->X;
1426 }
1427 if (Buff->MaxX <= Start->X + Length)
1428 {
1429 UpdateRect->right = Buff->MaxX - 1;
1430 }
1431 else
1432 {
1433 UpdateRect->right = Start->X + Length - 1;
1434 }
1435 UpdateRect->top = Start->Y;
1436 UpdateRect->bottom = Start->Y+ (Start->X + Length - 1) / Buff->MaxX;
1437 if (Buff->MaxY <= UpdateRect->bottom)
1438 {
1439 UpdateRect->bottom = Buff->MaxY - 1;
1440 }
1441 }
1442
1443 CSR_API(CsrWriteConsoleOutputChar)
1444 {
1445 NTSTATUS Status;
1446 PBYTE String = Request->Data.WriteConsoleOutputCharRequest.String;
1447 PBYTE Buffer;
1448 PCSRSS_CONSOLE Console;
1449 PCSRSS_SCREEN_BUFFER Buff;
1450 DWORD X, Y, Length;
1451 RECT UpdateRect;
1452
1453 DPRINT("CsrWriteConsoleOutputChar\n");
1454
1455 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1456 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1457 sizeof(LPC_MESSAGE);
1458
1459 if (Request->Header.DataSize
1460 < sizeof(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR_REQUEST) - 1
1461 + Request->Data.WriteConsoleOutputCharRequest.Length)
1462 {
1463 DPRINT1("Invalid request size\n");
1464 return Reply->Status = STATUS_INVALID_PARAMETER;
1465 }
1466
1467 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1468 if (! NT_SUCCESS(Status))
1469 {
1470 return Reply->Status = Status;
1471 }
1472
1473 Status = ConioLockScreenBuffer(ProcessData,
1474 Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle,
1475 &Buff);
1476 if (! NT_SUCCESS(Status))
1477 {
1478 if (NULL != Console)
1479 {
1480 ConioUnlockConsole(Console);
1481 }
1482 return Reply->Status = Status;
1483 }
1484
1485 X = Request->Data.WriteConsoleOutputCharRequest.Coord.X + Buff->ShowX;
1486 Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1487 Length = Request->Data.WriteConsoleOutputCharRequest.Length;
1488 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1489 while (Length--)
1490 {
1491 *Buffer = *String++;
1492 Buffer += 2;
1493 if (++X == Buff->MaxX)
1494 {
1495 if (++Y == Buff->MaxY)
1496 {
1497 Y = 0;
1498 Buffer = Buff->Buffer;
1499 }
1500 X = 0;
1501 }
1502 }
1503
1504 if (NULL != Console && Buff == Console->ActiveBuffer)
1505 {
1506 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputCharRequest.Coord,
1507 Request->Data.WriteConsoleOutputCharRequest.Length);
1508 ConioDrawRegion(Console, &UpdateRect);
1509 }
1510
1511 Reply->Data.WriteConsoleOutputCharReply.EndCoord.X = X - Buff->ShowX;
1512 Reply->Data.WriteConsoleOutputCharReply.EndCoord.Y = (Y + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1513
1514 ConioUnlockScreenBuffer(Buff);
1515 if (NULL != Console)
1516 {
1517 ConioUnlockConsole(Console);
1518 }
1519
1520 return Reply->Status = STATUS_SUCCESS;
1521 }
1522
1523 CSR_API(CsrFillOutputChar)
1524 {
1525 NTSTATUS Status;
1526 PCSRSS_CONSOLE Console;
1527 PCSRSS_SCREEN_BUFFER Buff;
1528 DWORD X, Y, Length;
1529 BYTE Char;
1530 PBYTE Buffer;
1531 RECT UpdateRect;
1532
1533 DPRINT("CsrFillOutputChar\n");
1534
1535 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1536 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1537
1538 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1539 if (! NT_SUCCESS(Status))
1540 {
1541 return Reply->Status = Status;
1542 }
1543
1544 Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, &Buff);
1545 if (! NT_SUCCESS(Status))
1546 {
1547 if (NULL != Console)
1548 {
1549 ConioUnlockConsole(Console);
1550 }
1551 return Reply->Status = Status;
1552 }
1553
1554 X = Request->Data.FillOutputRequest.Position.X + Buff->ShowX;
1555 Y = (Request->Data.FillOutputRequest.Position.Y + Buff->ShowY) % Buff->MaxY;
1556 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1557 Char = Request->Data.FillOutputRequest.Char;
1558 Length = Request->Data.FillOutputRequest.Length;
1559 while (Length--)
1560 {
1561 *Buffer = Char;
1562 Buffer += 2;
1563 if (++X == Buff->MaxX)
1564 {
1565 if (++Y == Buff->MaxY)
1566 {
1567 Y = 0;
1568 Buffer = Buff->Buffer;
1569 }
1570 X = 0;
1571 }
1572 }
1573
1574 if (NULL != Console && Buff == Console->ActiveBuffer)
1575 {
1576 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputRequest.Position,
1577 Request->Data.FillOutputRequest.Length);
1578 ConioDrawRegion(Console, &UpdateRect);
1579 }
1580
1581 ConioUnlockScreenBuffer(Buff);
1582 if (NULL != Console)
1583 {
1584 ConioUnlockConsole(Console);
1585 }
1586
1587 return Reply->Status;
1588 }
1589
1590 CSR_API(CsrReadInputEvent)
1591 {
1592 PLIST_ENTRY CurrentEntry;
1593 PCSRSS_CONSOLE Console;
1594 NTSTATUS Status;
1595 BOOLEAN Done = FALSE;
1596 ConsoleInput *Input;
1597
1598 DPRINT("CsrReadInputEvent\n");
1599
1600 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1601 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1602 Reply->Data.ReadInputReply.Event = ProcessData->ConsoleEvent;
1603
1604 Status = ConioLockConsole(ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, &Console);
1605 if (! NT_SUCCESS(Status))
1606 {
1607 return Reply->Status = Status;
1608 }
1609
1610 /* only get input if there is any */
1611 while (Console->InputEvents.Flink != &Console->InputEvents && ! Done)
1612 {
1613 CurrentEntry = RemoveHeadList(&Console->InputEvents);
1614 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1615 Done = !Input->Fake;
1616 Reply->Data.ReadInputReply.Input = Input->InputEvent;
1617
1618 if (Input->InputEvent.EventType == KEY_EVENT)
1619 {
1620 if (0 != (Console->Mode & ENABLE_LINE_INPUT)
1621 && Input->InputEvent.Event.KeyEvent.bKeyDown
1622 && '\r' == Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1623 {
1624 Console->WaitingLines--;
1625 }
1626 Console->WaitingChars--;
1627 }
1628 HeapFree(Win32CsrApiHeap, 0, Input);
1629
1630 Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents);
1631 Status = STATUS_SUCCESS;
1632 Console->EarlyReturn = FALSE; /* clear early return */
1633 }
1634
1635 if (! Done)
1636 {
1637 Status = STATUS_PENDING;
1638 Console->EarlyReturn = TRUE; /* mark for early return */
1639 }
1640
1641 ConioUnlockConsole(Console);
1642
1643 return Reply->Status = Status;
1644 }
1645
1646 CSR_API(CsrWriteConsoleOutputAttrib)
1647 {
1648 PCSRSS_CONSOLE Console;
1649 PCSRSS_SCREEN_BUFFER Buff;
1650 PUCHAR Buffer, Attribute;
1651 int X, Y, Length;
1652 NTSTATUS Status;
1653 RECT UpdateRect;
1654
1655 DPRINT("CsrWriteConsoleOutputAttrib\n");
1656
1657 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1658 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) -
1659 sizeof(LPC_MESSAGE);
1660
1661 if (Request->Header.DataSize
1662 < sizeof(CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB_REQUEST) - 1
1663 + Request->Data.WriteConsoleOutputAttribRequest.Length)
1664 {
1665 DPRINT1("Invalid request size\n");
1666 return Reply->Status = STATUS_INVALID_PARAMETER;
1667 }
1668
1669 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1670 if (! NT_SUCCESS(Status))
1671 {
1672 return Reply->Status = Status;
1673 }
1674
1675 Status = ConioLockScreenBuffer(ProcessData,
1676 Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle,
1677 &Buff);
1678 if (! NT_SUCCESS(Status))
1679 {
1680 if (NULL != Console)
1681 {
1682 ConioUnlockConsole(Console);
1683 }
1684 return Reply->Status = Status;
1685 }
1686
1687 X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X + Buff->ShowX;
1688 Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1689 Length = Request->Data.WriteConsoleOutputAttribRequest.Length;
1690 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
1691 Attribute = Request->Data.WriteConsoleOutputAttribRequest.String;
1692 while (Length--)
1693 {
1694 *Buffer = *Attribute++;
1695 Buffer += 2;
1696 if (++X == Buff->MaxX)
1697 {
1698 if (++Y == Buff->MaxY)
1699 {
1700 Y = 0;
1701 Buffer = Buff->Buffer + 1;
1702 }
1703 X = 0;
1704 }
1705 }
1706
1707 if (NULL != Console && Buff == Console->ActiveBuffer)
1708 {
1709 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1710 Request->Data.WriteConsoleOutputAttribRequest.Length);
1711 ConioDrawRegion(Console, &UpdateRect);
1712 }
1713
1714 if (NULL != Console)
1715 {
1716 ConioUnlockConsole(Console);
1717 }
1718
1719 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1720 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1721
1722 ConioUnlockScreenBuffer(Buff);
1723
1724 return Reply->Status = STATUS_SUCCESS;
1725 }
1726
1727 CSR_API(CsrFillOutputAttrib)
1728 {
1729 PCSRSS_SCREEN_BUFFER Buff;
1730 PCHAR Buffer;
1731 NTSTATUS Status;
1732 int X, Y, Length;
1733 UCHAR Attr;
1734 RECT UpdateRect;
1735 PCSRSS_CONSOLE Console;
1736
1737 DPRINT("CsrFillOutputAttrib\n");
1738
1739 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1740 if (! NT_SUCCESS(Status))
1741 {
1742 return Reply->Status = Status;
1743 }
1744
1745 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1746 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1747 Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, &Buff);
1748 if (! NT_SUCCESS(Status))
1749 {
1750 if (NULL != Console)
1751 {
1752 ConioUnlockConsole(Console);
1753 }
1754 return Reply->Status = Status;
1755 }
1756
1757 X = Request->Data.FillOutputAttribRequest.Coord.X + Buff->ShowX;
1758 Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1759 Length = Request->Data.FillOutputAttribRequest.Length;
1760 Attr = Request->Data.FillOutputAttribRequest.Attribute;
1761 Buffer = &Buff->Buffer[(Y * Buff->MaxX * 2) + (X * 2) + 1];
1762 while (Length--)
1763 {
1764 *Buffer = Attr;
1765 Buffer += 2;
1766 if (++X == Buff->MaxX)
1767 {
1768 if (++Y == Buff->MaxY)
1769 {
1770 Y = 0;
1771 Buffer = Buff->Buffer + 1;
1772 }
1773 X = 0;
1774 }
1775 }
1776
1777 if (NULL != Console && Buff == Console->ActiveBuffer)
1778 {
1779 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputAttribRequest.Coord,
1780 Request->Data.FillOutputAttribRequest.Length);
1781 ConioDrawRegion(Console, &UpdateRect);
1782 }
1783
1784 ConioUnlockScreenBuffer(Buff);
1785 if (NULL != Console)
1786 {
1787 ConioUnlockConsole(Console);
1788 }
1789
1790 return Reply->Status = STATUS_SUCCESS;
1791 }
1792
1793
1794 CSR_API(CsrGetCursorInfo)
1795 {
1796 PCSRSS_SCREEN_BUFFER Buff;
1797 NTSTATUS Status;
1798
1799 DPRINT("CsrGetCursorInfo\n");
1800
1801 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1802 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1803
1804 Status = ConioLockScreenBuffer(ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, &Buff);
1805 if (! NT_SUCCESS(Status))
1806 {
1807 return Reply->Status = Status;
1808 }
1809 Reply->Data.GetCursorInfoReply.Info = Buff->CursorInfo;
1810 ConioUnlockScreenBuffer(Buff);
1811
1812 return Reply->Status = STATUS_SUCCESS;
1813 }
1814
1815 CSR_API(CsrSetCursorInfo)
1816 {
1817 PCSRSS_CONSOLE Console;
1818 PCSRSS_SCREEN_BUFFER Buff;
1819 DWORD Size;
1820 BOOL Visible;
1821 NTSTATUS Status;
1822
1823 DPRINT("CsrSetCursorInfo\n");
1824
1825 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1826 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1827
1828 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1829 if (! NT_SUCCESS(Status))
1830 {
1831 return Reply->Status = Status;
1832 }
1833
1834 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorInfoRequest.ConsoleHandle, &Buff);
1835 if (! NT_SUCCESS(Status))
1836 {
1837 if (NULL != Console)
1838 {
1839 ConioUnlockConsole(Console);
1840 }
1841 return Reply->Status = Status;
1842 }
1843
1844 Size = Request->Data.SetCursorInfoRequest.Info.dwSize;
1845 Visible = Request->Data.SetCursorInfoRequest.Info.bVisible;
1846 if (Size < 1)
1847 {
1848 Size = 1;
1849 }
1850 if (100 < Size)
1851 {
1852 Size = 100;
1853 }
1854
1855 if (Size != Buff->CursorInfo.dwSize
1856 || (Visible && ! Buff->CursorInfo.bVisible) || (! Visible && Buff->CursorInfo.bVisible))
1857 {
1858 Buff->CursorInfo.dwSize = Size;
1859 Buff->CursorInfo.bVisible = Visible;
1860
1861 if (NULL != Console && ! ConioSetCursorInfo(Console, Buff))
1862 {
1863 ConioUnlockScreenBuffer(Buff);
1864 ConioUnlockConsole(Console);
1865 return Reply->Status = STATUS_UNSUCCESSFUL;
1866 }
1867 }
1868
1869 ConioUnlockScreenBuffer(Buff);
1870 if (NULL != Console)
1871 {
1872 ConioUnlockConsole(Console);
1873 }
1874
1875 return Reply->Status = STATUS_SUCCESS;
1876 }
1877
1878 CSR_API(CsrSetTextAttrib)
1879 {
1880 NTSTATUS Status;
1881 PCSRSS_CONSOLE Console;
1882 PCSRSS_SCREEN_BUFFER Buff;
1883 LONG OldCursorX, OldCursorY;
1884
1885 DPRINT("CsrSetTextAttrib\n");
1886
1887 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1888 if (! NT_SUCCESS(Status))
1889 {
1890 return Reply->Status = Status;
1891 }
1892
1893 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff);
1894 if (! NT_SUCCESS(Status))
1895 {
1896 if (NULL != Console)
1897 {
1898 ConioUnlockConsole(Console);
1899 }
1900 return Reply->Status = Status;
1901 }
1902
1903 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &OldCursorX, &OldCursorY);
1904
1905 Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1906 if (NULL != Console && Buff == Console->ActiveBuffer)
1907 {
1908 if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
1909 {
1910 ConioUnlockScreenBuffer(Buff);
1911 ConioUnlockConsole(Console);
1912 return Reply->Status = STATUS_UNSUCCESSFUL;
1913 }
1914 }
1915
1916 ConioUnlockScreenBuffer(Buff);
1917 if (NULL != Console)
1918 {
1919 ConioUnlockConsole(Console);
1920 }
1921
1922 return Reply->Status = STATUS_SUCCESS;
1923 }
1924
1925 CSR_API(CsrSetConsoleMode)
1926 {
1927 NTSTATUS Status;
1928 PCSRSS_CONSOLE Console;
1929 PCSRSS_SCREEN_BUFFER Buff;
1930
1931 DPRINT("CsrSetConsoleMode\n");
1932
1933 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1934 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1935 Status = Win32CsrGetObject(ProcessData,
1936 Request->Data.SetConsoleModeRequest.ConsoleHandle,
1937 (Object_t **) &Console);
1938 if (! NT_SUCCESS(Status))
1939 {
1940 return Reply->Status = Status;
1941 }
1942
1943 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1944 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
1945 {
1946 Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1947 }
1948 else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
1949 {
1950 Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1951 }
1952 else
1953 {
1954 return Reply->Status = STATUS_INVALID_HANDLE;
1955 }
1956
1957 Reply->Status = STATUS_SUCCESS;
1958
1959 return Reply->Status;
1960 }
1961
1962 CSR_API(CsrGetConsoleMode)
1963 {
1964 NTSTATUS Status;
1965 PCSRSS_CONSOLE Console;
1966 PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
1967
1968 DPRINT("CsrGetConsoleMode\n");
1969
1970 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1971 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
1972 Status = Win32CsrGetObject(ProcessData, Request->Data.GetConsoleModeRequest.ConsoleHandle,
1973 (Object_t **) &Console);
1974 if (! NT_SUCCESS(Status))
1975 {
1976 return Reply->Status = Status;
1977 }
1978 Reply->Status = STATUS_SUCCESS;
1979 Buff = (PCSRSS_SCREEN_BUFFER) Console;
1980 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
1981 {
1982 Reply->Data.GetConsoleModeReply.ConsoleMode = Console->Mode;
1983 }
1984 else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
1985 {
1986 Reply->Data.GetConsoleModeReply.ConsoleMode = Buff->Mode;
1987 }
1988 else
1989 {
1990 Reply->Status = STATUS_INVALID_HANDLE;
1991 }
1992
1993 return Reply->Status;
1994 }
1995
1996 CSR_API(CsrCreateScreenBuffer)
1997 {
1998 PCSRSS_CONSOLE Console;
1999 PCSRSS_SCREEN_BUFFER Buff;
2000 NTSTATUS Status;
2001
2002 DPRINT("CsrCreateScreenBuffer\n");
2003
2004 if (ProcessData == NULL)
2005 {
2006 return Reply->Status = STATUS_INVALID_PARAMETER;
2007 }
2008
2009 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2010 if (! NT_SUCCESS(Status))
2011 {
2012 return Reply->Status = Status;
2013 }
2014 if (NULL == Console)
2015 {
2016 return Reply->Status = STATUS_INVALID_HANDLE;
2017 }
2018
2019 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2020 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2021
2022 Buff = HeapAlloc(Win32CsrApiHeap, 0, sizeof(CSRSS_SCREEN_BUFFER));
2023 if (NULL == Buff)
2024 {
2025 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
2026 }
2027
2028 Status = CsrInitConsoleScreenBuffer(Console, Buff);
2029 if(! NT_SUCCESS(Status))
2030 {
2031 Reply->Status = Status;
2032 }
2033 else
2034 {
2035 Reply->Status = Win32CsrInsertObject(ProcessData, &Reply->Data.CreateScreenBufferReply.OutputHandle, &Buff->Header);
2036 }
2037
2038 ConioUnlockConsole(Console);
2039
2040 return Reply->Status;
2041 }
2042
2043 CSR_API(CsrSetScreenBuffer)
2044 {
2045 NTSTATUS Status;
2046 PCSRSS_CONSOLE Console;
2047 PCSRSS_SCREEN_BUFFER Buff;
2048
2049 DPRINT("CsrSetScreenBuffer\n");
2050
2051 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2052 if (! NT_SUCCESS(Status))
2053 {
2054 return Reply->Status = Status;
2055 }
2056 if (NULL == Console)
2057 {
2058 DPRINT1("Trying to set screen buffer for app without console\n");
2059 return Reply->Status = STATUS_INVALID_HANDLE;
2060 }
2061
2062 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2063 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2064
2065 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetScreenBufferRequest.OutputHandle, &Buff);
2066 if (! NT_SUCCESS(Status))
2067 {
2068 ConioUnlockConsole(Console);
2069 return Reply->Status;
2070 }
2071
2072 if (Buff == Console->ActiveBuffer)
2073 {
2074 ConioUnlockScreenBuffer(Buff);
2075 ConioUnlockConsole(Console);
2076 return STATUS_SUCCESS;
2077 }
2078
2079 /* drop reference to old buffer, maybe delete */
2080 if (! InterlockedDecrement(&Console->ActiveBuffer->Header.ReferenceCount))
2081 {
2082 ConioDeleteScreenBuffer((Object_t *) Console->ActiveBuffer);
2083 }
2084 /* tie console to new buffer */
2085 Console->ActiveBuffer = Buff;
2086 /* inc ref count on new buffer */
2087 InterlockedIncrement(&Buff->Header.ReferenceCount);
2088 /* Redraw the console */
2089 ConioDrawConsole(Console);
2090
2091 ConioUnlockScreenBuffer(Buff);
2092 ConioUnlockConsole(Console);
2093
2094 return Reply->Status = STATUS_SUCCESS;
2095 }
2096
2097 CSR_API(CsrSetTitle)
2098 {
2099 NTSTATUS Status;
2100 PCSRSS_CONSOLE Console;
2101
2102 DPRINT("CsrSetTitle\n");
2103
2104 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2105 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2106
2107 if (Request->Header.DataSize
2108 < sizeof(CSRSS_SET_TITLE_REQUEST) - 1
2109 + Request->Data.SetTitleRequest.Length)
2110 {
2111 DPRINT1("Invalid request size\n");
2112 return Reply->Status = STATUS_INVALID_PARAMETER;
2113 }
2114
2115 Status = ConioLockConsole(ProcessData, Request->Data.SetTitleRequest.Console, &Console);
2116 if(! NT_SUCCESS(Status))
2117 {
2118 Reply->Status = Status;
2119 }
2120 else
2121 {
2122 /* copy title to console */
2123 RtlFreeUnicodeString(&Console->Title);
2124 RtlCreateUnicodeString(&Console->Title, Request->Data.SetTitleRequest.Title);
2125 if (! ConioChangeTitle(Console))
2126 {
2127 Reply->Status = STATUS_UNSUCCESSFUL;
2128 }
2129 else
2130 {
2131 Reply->Status = STATUS_SUCCESS;
2132 }
2133 }
2134 ConioUnlockConsole(Console);
2135
2136 return Reply->Status;
2137 }
2138
2139 CSR_API(CsrGetTitle)
2140 {
2141 NTSTATUS Status;
2142 PCSRSS_CONSOLE Console;
2143
2144 DPRINT("CsrGetTitle\n");
2145
2146 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2147 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2148 Status = ConioLockConsole(ProcessData,
2149 Request->Data.GetTitleRequest.ConsoleHandle,
2150 &Console);
2151 if (! NT_SUCCESS(Status))
2152 {
2153 DPRINT1("Can't get console\n");
2154 return Reply->Status = Status;
2155 }
2156
2157 /* Copy title of the console to the user title buffer */
2158 RtlZeroMemory(&Reply->Data.GetTitleReply, sizeof(CSRSS_GET_TITLE_REPLY));
2159 Reply->Data.GetTitleReply.ConsoleHandle = Request->Data.GetTitleRequest.ConsoleHandle;
2160 Reply->Data.GetTitleReply.Length = Console->Title.Length;
2161 wcscpy (Reply->Data.GetTitleReply.Title, Console->Title.Buffer);
2162 Reply->Header.MessageSize += Console->Title.Length;
2163 Reply->Header.DataSize += Console->Title.Length;
2164 Reply->Status = STATUS_SUCCESS;
2165
2166 ConioUnlockConsole(Console);
2167
2168 return Reply->Status;
2169 }
2170
2171 CSR_API(CsrWriteConsoleOutput)
2172 {
2173 SHORT i, X, Y, SizeX, SizeY;
2174 PCSRSS_CONSOLE Console;
2175 PCSRSS_SCREEN_BUFFER Buff;
2176 RECT ScreenBuffer;
2177 CHAR_INFO* CurCharInfo;
2178 RECT WriteRegion;
2179 CHAR_INFO* CharInfo;
2180 COORD BufferCoord;
2181 COORD BufferSize;
2182 NTSTATUS Status;
2183 DWORD Offset;
2184 DWORD PSize;
2185
2186 DPRINT("CsrWriteConsoleOutput\n");
2187
2188 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2189 if (! NT_SUCCESS(Status))
2190 {
2191 return Reply->Status = Status;
2192 }
2193
2194 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2195 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2196 Status = ConioLockScreenBuffer(ProcessData,
2197 Request->Data.WriteConsoleOutputRequest.ConsoleHandle,
2198 &Buff);
2199 if (! NT_SUCCESS(Status))
2200 {
2201 if (NULL != Console)
2202 {
2203 ConioUnlockConsole(Console);
2204 }
2205 return Reply->Status = Status;
2206 }
2207
2208 BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
2209 PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
2210 BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
2211 CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
2212 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
2213 (((PVOID)CharInfo + PSize) >
2214 (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2215 {
2216 ConioUnlockScreenBuffer(Buff);
2217 ConioUnlockConsole(Console);
2218 return Reply->Status = STATUS_ACCESS_VIOLATION;
2219 }
2220 WriteRegion.left = Request->Data.WriteConsoleOutputRequest.WriteRegion.Left;
2221 WriteRegion.top = Request->Data.WriteConsoleOutputRequest.WriteRegion.Top;
2222 WriteRegion.right = Request->Data.WriteConsoleOutputRequest.WriteRegion.Right;
2223 WriteRegion.bottom = Request->Data.WriteConsoleOutputRequest.WriteRegion.Bottom;
2224
2225 SizeY = RtlRosMin(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion));
2226 SizeX = RtlRosMin(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion));
2227 WriteRegion.bottom = WriteRegion.top + SizeY - 1;
2228 WriteRegion.right = WriteRegion.left + SizeX - 1;
2229
2230 /* Make sure WriteRegion is inside the screen buffer */
2231 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
2232 if (! ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion))
2233 {
2234 ConioUnlockScreenBuffer(Buff);
2235 ConioUnlockConsole(Console);
2236
2237 /* It is okay to have a WriteRegion completely outside the screen buffer.
2238 No data is written then. */
2239 return Reply->Status = STATUS_SUCCESS;
2240 }
2241
2242 for (i = 0, Y = WriteRegion.top; Y <= WriteRegion.bottom; i++, Y++)
2243 {
2244 CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
2245 Offset = (((Y + Buff->ShowY) % Buff->MaxY) * Buff->MaxX + WriteRegion.left) * 2;
2246 for (X = WriteRegion.left; X <= WriteRegion.right; X++)
2247 {
2248 SET_CELL_BUFFER(Buff, Offset, CurCharInfo->Char.AsciiChar, CurCharInfo->Attributes);
2249 CurCharInfo++;
2250 }
2251 }
2252
2253 if (NULL != Console)
2254 {
2255 ConioDrawRegion(Console, &WriteRegion);
2256 }
2257
2258 ConioUnlockScreenBuffer(Buff);
2259 ConioUnlockConsole(Console);
2260
2261 Reply->Data.WriteConsoleOutputReply.WriteRegion.Right = WriteRegion.left + SizeX - 1;
2262 Reply->Data.WriteConsoleOutputReply.WriteRegion.Bottom = WriteRegion.top + SizeY - 1;
2263 Reply->Data.WriteConsoleOutputReply.WriteRegion.Left = WriteRegion.left;
2264 Reply->Data.WriteConsoleOutputReply.WriteRegion.Top = WriteRegion.top;
2265
2266 return Reply->Status = STATUS_SUCCESS;
2267 }
2268
2269 CSR_API(CsrFlushInputBuffer)
2270 {
2271 PLIST_ENTRY CurrentEntry;
2272 PCSRSS_CONSOLE Console;
2273 ConsoleInput* Input;
2274 NTSTATUS Status;
2275
2276 DPRINT("CsrFlushInputBuffer\n");
2277
2278 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2279 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2280 Status = ConioLockConsole(ProcessData,
2281 Request->Data.FlushInputBufferRequest.ConsoleInput,
2282 &Console);
2283 if(! NT_SUCCESS(Status))
2284 {
2285 return Reply->Status = Status;
2286 }
2287
2288 /* Discard all entries in the input event queue */
2289 while (!IsListEmpty(&Console->InputEvents))
2290 {
2291 CurrentEntry = RemoveHeadList(&Console->InputEvents);
2292 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
2293 /* Destroy the event */
2294 HeapFree(Win32CsrApiHeap, 0, Input);
2295 }
2296 Console->WaitingChars=0;
2297
2298 ConioUnlockConsole(Console);
2299
2300 return Reply->Status = STATUS_SUCCESS;
2301 }
2302
2303 CSR_API(CsrScrollConsoleScreenBuffer)
2304 {
2305 PCSRSS_CONSOLE Console;
2306 PCSRSS_SCREEN_BUFFER Buff;
2307 RECT ScreenBuffer;
2308 RECT SrcRegion;
2309 RECT DstRegion;
2310 RECT FillRegion;
2311 RECT ScrollRectangle;
2312 RECT ClipRectangle;
2313 NTSTATUS Status;
2314 BOOLEAN DoFill;
2315
2316 DPRINT("CsrScrollConsoleScreenBuffer\n");
2317
2318 ALIAS(ConsoleHandle,Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle);
2319 ALIAS(UseClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle);
2320 ALIAS(DestinationOrigin,Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin);
2321 ALIAS(Fill,Request->Data.ScrollConsoleScreenBufferRequest.Fill);
2322
2323 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2324 if (! NT_SUCCESS(Status))
2325 {
2326 return Reply->Status = Status;
2327 }
2328
2329 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2330 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2331 Status = ConioLockScreenBuffer(ProcessData, ConsoleHandle, &Buff);
2332 if (! NT_SUCCESS(Status))
2333 {
2334 if (NULL != Console)
2335 {
2336 ConioUnlockConsole(Console);
2337 }
2338 return Reply->Status = Status;
2339 }
2340
2341 ScrollRectangle.left = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Left;
2342 ScrollRectangle.top = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Top;
2343 ScrollRectangle.right = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Right;
2344 ScrollRectangle.bottom = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Bottom;
2345 ClipRectangle.left = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Left;
2346 ClipRectangle.top = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Top;
2347 ClipRectangle.right = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Right;
2348 ClipRectangle.bottom = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Bottom;
2349
2350 /* Make sure source rectangle is inside the screen buffer */
2351 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
2352 if (! ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle))
2353 {
2354 ConioUnlockScreenBuffer(Buff);
2355 return Reply->Status = STATUS_INVALID_PARAMETER;
2356 }
2357
2358 if (UseClipRectangle && ! ConioGetIntersection(&SrcRegion, &SrcRegion, &ClipRectangle))
2359 {
2360 ConioUnlockScreenBuffer(Buff);
2361 return Reply->Status = STATUS_SUCCESS;
2362 }
2363
2364
2365 ConioInitRect(&DstRegion,
2366 DestinationOrigin.Y,
2367 DestinationOrigin.X,
2368 DestinationOrigin.Y + ConioRectHeight(&ScrollRectangle) - 1,
2369 DestinationOrigin.X + ConioRectWidth(&ScrollRectangle) - 1);
2370
2371 /* Make sure destination rectangle is inside the screen buffer */
2372 if (! ConioGetIntersection(&DstRegion, &DstRegion, &ScreenBuffer))
2373 {
2374 ConioUnlockScreenBuffer(Buff);
2375 return Reply->Status = STATUS_INVALID_PARAMETER;
2376 }
2377
2378 ConioCopyRegion(Buff, &SrcRegion, &DstRegion);
2379
2380 /* Get the region that should be filled with the specified character and attributes */
2381
2382 DoFill = FALSE;
2383
2384 ConioGetUnion(&FillRegion, &SrcRegion, &DstRegion);
2385
2386 if (ConioSubtractRect(&FillRegion, &FillRegion, &DstRegion))
2387 {
2388 /* FIXME: The subtracted rectangle is off by one line */
2389 FillRegion.top += 1;
2390
2391 ConioFillRegion(Buff, &FillRegion, Fill);
2392 DoFill = TRUE;
2393 }
2394
2395 if (NULL != Console && Buff == Console->ActiveBuffer)
2396 {
2397 /* Draw destination region */
2398 ConioDrawRegion(Console, &DstRegion);
2399
2400 if (DoFill)
2401 {
2402 /* Draw filled region */
2403 ConioDrawRegion(Console, &FillRegion);
2404 }
2405 }
2406
2407 ConioUnlockScreenBuffer(Buff);
2408 if (NULL != Console)
2409 {
2410 ConioUnlockConsole(Console);
2411 }
2412
2413 return Reply->Status = STATUS_SUCCESS;
2414 }
2415
2416 CSR_API(CsrReadConsoleOutputChar)
2417 {
2418 NTSTATUS Status;
2419 PCSRSS_SCREEN_BUFFER Buff;
2420 DWORD Xpos, Ypos;
2421 BYTE* ReadBuffer;
2422 DWORD i;
2423
2424 DPRINT("CsrReadConsoleOutputChar\n");
2425
2426 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2427 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2428 ReadBuffer = Reply->Data.ReadConsoleOutputCharReply.String;
2429
2430 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, Buff);
2431 if (! NT_SUCCESS(Status))
2432 {
2433 return Reply->Status = Status;
2434 }
2435
2436 Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X + Buff->ShowX;
2437 Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + Buff->ShowY) % Buff->MaxY;
2438
2439 for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
2440 {
2441 *ReadBuffer = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX)];
2442
2443 ReadBuffer++;
2444 Xpos++;
2445
2446 if (Xpos == Buff->MaxX)
2447 {
2448 Xpos = 0;
2449 Ypos++;
2450
2451 if (Ypos == Buff->MaxY)
2452 {
2453 Ypos = 0;
2454 }
2455 }
2456 }
2457
2458 *ReadBuffer = 0;
2459 Reply->Status = STATUS_SUCCESS;
2460 Reply->Data.ReadConsoleOutputCharReply.EndCoord.X = Xpos - Buff->ShowX;
2461 Reply->Data.ReadConsoleOutputCharReply.EndCoord.Y = (Ypos - Buff->ShowY + Buff->MaxY) % Buff->MaxY;
2462 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2463 Reply->Header.DataSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2464
2465 ConioUnlockScreenBuffer(Buff);
2466
2467 return Reply->Status;
2468 }
2469
2470
2471 CSR_API(CsrReadConsoleOutputAttrib)
2472 {
2473 NTSTATUS Status;
2474 PCSRSS_SCREEN_BUFFER Buff;
2475 DWORD Xpos, Ypos;
2476 CHAR* ReadBuffer;
2477 DWORD i;
2478
2479 DPRINT("CsrReadConsoleOutputAttrib\n");
2480
2481 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2482 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2483 ReadBuffer = Reply->Data.ReadConsoleOutputAttribReply.String;
2484
2485 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, &Buff);
2486 if (! NT_SUCCESS(Status))
2487 {
2488 return Reply->Status = Status;
2489 }
2490
2491 Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X + Buff->ShowX;
2492 Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + Buff->ShowY) % Buff->MaxY;
2493
2494 for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2495 {
2496 *ReadBuffer = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX) + 1];
2497
2498 ReadBuffer++;
2499 Xpos++;
2500
2501 if (Xpos == Buff->MaxX)
2502 {
2503 Xpos = 0;
2504 Ypos++;
2505
2506 if (Ypos == Buff->MaxY)
2507 {
2508 Ypos = 0;
2509 }
2510 }
2511 }
2512
2513 *ReadBuffer = 0;
2514
2515 Reply->Status = STATUS_SUCCESS;
2516 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.X = Xpos - Buff->ShowX;
2517 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.Y = (Ypos - Buff->ShowY + Buff->MaxY) % Buff->MaxY;
2518 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2519 Reply->Header.DataSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2520
2521 ConioUnlockScreenBuffer(Buff);
2522
2523 return Reply->Status;
2524 }
2525
2526
2527 CSR_API(CsrGetNumberOfConsoleInputEvents)
2528 {
2529 NTSTATUS Status;
2530 PCSRSS_CONSOLE Console;
2531 PLIST_ENTRY CurrentItem;
2532 DWORD NumEvents;
2533 ConsoleInput *Input;
2534
2535 DPRINT("CsrGetNumberOfConsoleInputEvents\n");
2536
2537 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2538 Reply->Header.DataSize = Reply->Header.MessageSize - sizeof(LPC_MESSAGE);
2539
2540 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console);
2541 if (! NT_SUCCESS(Status))
2542 {
2543 return Reply->Status = Status;
2544 }
2545
2546 CurrentItem = Console->InputEvents.Flink;
2547 NumEvents = 0;
2548
2549 /* If there are any events ... */
2550 while (CurrentItem != &Console->InputEvents)
2551 {
2552 Input = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2553 CurrentItem = CurrentItem->Flink;
2554 if (!Input->Fake)
2555 {
2556 NumEvents++;
2557 }
2558 }
2559
2560 ConioUnlockConsole(Console);
2561
2562 Reply->Status = STATUS_SUCCESS;
2563 Reply->Data.GetNumInputEventsReply.NumInputEvents = NumEvents;
2564
2565 return Reply->Status;
2566 }
2567
2568
2569 CSR_API(CsrPeekConsoleInput)
2570 {
2571 NTSTATUS Status;
2572 PCSRSS_CONSOLE Console;
2573 DWORD Size;
2574 DWORD Length;
2575 PLIST_ENTRY CurrentItem;
2576 PINPUT_RECORD InputRecord;
2577 ConsoleInput* Item;
2578 UINT NumItems;
2579
2580 DPRINT("CsrPeekConsoleInput\n");
2581
2582 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2583 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2584
2585 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console);
2586 if(! NT_SUCCESS(Status))
2587 {
2588 return Reply->Status = Status;
2589 }
2590
2591 InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2592 Length = Request->Data.PeekConsoleInputRequest.Length;
2593 Size = Length * sizeof(INPUT_RECORD);
2594
2595 if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2596 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2597 {
2598 ConioUnlockConsole(Console);
2599 Reply->Status = STATUS_ACCESS_VIOLATION;
2600 return Reply->Status ;
2601 }
2602
2603 NumItems = 0;
2604
2605 if (! IsListEmpty(&Console->InputEvents))
2606 {
2607 CurrentItem = &Console->InputEvents;
2608
2609 while (NumItems < Length)
2610 {
2611 ++NumItems;
2612 Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2613 *InputRecord++ = Item->InputEvent;
2614
2615 if (CurrentItem->Flink == &Console->InputEvents)
2616 {
2617 break;
2618 }
2619 else
2620 {
2621 CurrentItem = CurrentItem->Flink;
2622 }
2623 }
2624 }
2625
2626 ConioUnlockConsole(Console);
2627
2628 Reply->Status = STATUS_SUCCESS;
2629 Reply->Data.PeekConsoleInputReply.Length = NumItems;
2630
2631 return Reply->Status;
2632 }
2633
2634
2635 CSR_API(CsrReadConsoleOutput)
2636 {
2637 PCHAR_INFO CharInfo;
2638 PCHAR_INFO CurCharInfo;
2639 PCSRSS_SCREEN_BUFFER Buff;
2640 DWORD Size;
2641 DWORD Length;
2642 DWORD SizeX, SizeY;
2643 NTSTATUS Status;
2644 COORD BufferSize;
2645 COORD BufferCoord;
2646 RECT ReadRegion;
2647 RECT ScreenRect;
2648 DWORD i, Y, X, Offset;
2649
2650 DPRINT("CsrReadConsoleOutput\n");
2651
2652 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2653 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2654
2655 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, &Buff);
2656 if (! NT_SUCCESS(Status))
2657 {
2658 return Reply->Status = Status;
2659 }
2660
2661 CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
2662 ReadRegion.left = Request->Data.ReadConsoleOutputRequest.ReadRegion.Left;
2663 ReadRegion.top = Request->Data.ReadConsoleOutputRequest.ReadRegion.Top;
2664 ReadRegion.right = Request->Data.ReadConsoleOutputRequest.ReadRegion.Right;
2665 ReadRegion.bottom = Request->Data.ReadConsoleOutputRequest.ReadRegion.Bottom;
2666 BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
2667 BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
2668 Length = BufferSize.X * BufferSize.Y;
2669 Size = Length * sizeof(CHAR_INFO);
2670
2671 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
2672 || (((PVOID)CharInfo + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2673 {
2674 ConioUnlockScreenBuffer(Buff);
2675 Reply->Status = STATUS_ACCESS_VIOLATION;
2676 return Reply->Status ;
2677 }
2678
2679 SizeY = RtlRosMin(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion));
2680 SizeX = RtlRosMin(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion));
2681 ReadRegion.bottom = ReadRegion.top + SizeY;
2682 ReadRegion.right = ReadRegion.left + SizeX;
2683
2684 ConioInitRect(&ScreenRect, 0, 0, Buff->MaxY, Buff->MaxX);
2685 if (! ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion))
2686 {
2687 ConioUnlockScreenBuffer(Buff);
2688 Reply->Status = STATUS_SUCCESS;
2689 return Reply->Status;
2690 }
2691
2692 for (i = 0, Y = ReadRegion.top; Y < ReadRegion.bottom; ++i, ++Y)
2693 {
2694 CurCharInfo = CharInfo + (i * BufferSize.X);
2695
2696 Offset = (((Y + Buff->ShowY) % Buff->MaxY) * Buff->MaxX + ReadRegion.left) * 2;
2697 for (X = ReadRegion.left; X < ReadRegion.right; ++X)
2698 {
2699 CurCharInfo->Char.AsciiChar = GET_CELL_BUFFER(Buff, Offset);
2700 CurCharInfo->Attributes = GET_CELL_BUFFER(Buff, Offset);
2701 ++CurCharInfo;
2702 }
2703 }
2704
2705 ConioUnlockScreenBuffer(Buff);
2706
2707 Reply->Status = STATUS_SUCCESS;
2708 Reply->Data.ReadConsoleOutputReply.ReadRegion.Right = ReadRegion.left + SizeX - 1;
2709 Reply->Data.ReadConsoleOutputReply.ReadRegion.Bottom = ReadRegion.top + SizeY - 1;
2710 Reply->Data.ReadConsoleOutputReply.ReadRegion.Left = ReadRegion.left;
2711 Reply->Data.ReadConsoleOutputReply.ReadRegion.Top = ReadRegion.top;
2712
2713 return Reply->Status;
2714 }
2715
2716
2717 CSR_API(CsrWriteConsoleInput)
2718 {
2719 PINPUT_RECORD InputRecord;
2720 PCSRSS_CONSOLE Console;
2721 NTSTATUS Status;
2722 DWORD Length;
2723 DWORD Size;
2724 DWORD i;
2725 ConsoleInput* Record;
2726
2727 DPRINT("CsrWriteConsoleInput\n");
2728
2729 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2730 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2731
2732 Status = ConioLockConsole(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, &Console);
2733 if (! NT_SUCCESS(Status))
2734 {
2735 return Reply->Status = Status;
2736 }
2737
2738 InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
2739 Length = Request->Data.WriteConsoleInputRequest.Length;
2740 Size = Length * sizeof(INPUT_RECORD);
2741
2742 if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2743 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2744 {
2745 ConioUnlockConsole(Console);
2746 Reply->Status = STATUS_ACCESS_VIOLATION;
2747 return Reply->Status ;
2748 }
2749
2750 for (i = 0; i < Length; i++)
2751 {
2752 Record = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
2753 if (NULL == Record)
2754 {
2755 ConioUnlockConsole(Console);
2756 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
2757 return Reply->Status;
2758 }
2759
2760 Record->Echoed = FALSE;
2761 Record->Fake = FALSE;
2762 Record->InputEvent = *InputRecord++;
2763 if (KEY_EVENT == Record->InputEvent.EventType)
2764 {
2765 ConioProcessChar(Console, Record);
2766 }
2767 }
2768
2769 ConioUnlockConsole(Console);
2770
2771 Reply->Status = STATUS_SUCCESS;
2772 Reply->Data.WriteConsoleInputReply.Length = i;
2773
2774 return Reply->Status;
2775 }
2776
2777 /**********************************************************************
2778 * HardwareStateProperty
2779 *
2780 * DESCRIPTION
2781 * Set/Get the value of the HardwareState and switch
2782 * between direct video buffer ouput and GDI windowed
2783 * output.
2784 * ARGUMENTS
2785 * Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
2786 * object. We use the same object to reply.
2787 * NOTE
2788 * ConsoleHwState has the correct size to be compatible
2789 * with NT's, but values are not.
2790 */
2791 STATIC NTSTATUS FASTCALL
2792 SetConsoleHardwareState (PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
2793 {
2794 DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
2795
2796 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
2797 ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
2798 {
2799 if (Console->HardwareState != ConsoleHwState)
2800 {
2801 /* TODO: implement switching from full screen to windowed mode */
2802 /* TODO: or back; now simply store the hardware state */
2803 Console->HardwareState = ConsoleHwState;
2804 }
2805
2806 return STATUS_SUCCESS;
2807 }
2808
2809 return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
2810 }
2811
2812 CSR_API(CsrHardwareStateProperty)
2813 {
2814 PCSRSS_CONSOLE Console;
2815 NTSTATUS Status;
2816
2817 DPRINT("CsrHardwareStateProperty\n");
2818
2819 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2820 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2821
2822 Status = ConioLockConsole(ProcessData,
2823 Request->Data.ConsoleHardwareStateRequest.ConsoleHandle,
2824 &Console);
2825 if (! NT_SUCCESS(Status))
2826 {
2827 DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
2828 return Reply->Status = Status;
2829 }
2830
2831 switch (Request->Data.ConsoleHardwareStateRequest.SetGet)
2832 {
2833 case CONSOLE_HARDWARE_STATE_GET:
2834 Reply->Data.ConsoleHardwareStateReply.State = Console->HardwareState;
2835 break;
2836
2837 case CONSOLE_HARDWARE_STATE_SET:
2838 DPRINT("Setting console hardware state.\n");
2839 Reply->Status = SetConsoleHardwareState(Console, Request->Data.ConsoleHardwareStateRequest.State);
2840 break;
2841
2842 default:
2843 Reply->Status = STATUS_INVALID_PARAMETER_2; /* Client: (handle, [set_get], mode) */
2844 break;
2845 }
2846
2847 ConioUnlockConsole(Console);
2848
2849 return Reply->Status;
2850 }
2851
2852 CSR_API(CsrGetConsoleWindow)
2853 {
2854 PCSRSS_CONSOLE Console;
2855 NTSTATUS Status;
2856
2857 DPRINT("CsrGetConsoleWindow\n");
2858
2859 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2860 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
2861
2862 Status = ConioLockConsole(ProcessData,
2863 Request->Data.ConsoleWindowRequest.ConsoleHandle,
2864 &Console);
2865 if (! NT_SUCCESS(Status))
2866 {
2867 return Reply->Status = Status;
2868 }
2869
2870 Reply->Data.ConsoleWindowReply.WindowHandle = Console->hWindow;
2871 ConioUnlockConsole(Console);
2872
2873 return Reply->Status = STATUS_SUCCESS;
2874 }
2875
2876 /* EOF */