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