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