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