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