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