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