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