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