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