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