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