2 * reactos/subsys/csrss/win32csr/conio.c
4 * Console I/O functions
6 * ReactOS Operating System
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 #define ConioInitRect(Rect, top, left, bottom, right) \
18 ((Rect)->Top) = top; \
19 ((Rect)->Left) = left; \
20 ((Rect)->Bottom) = bottom; \
21 ((Rect)->Right) = right
23 #define ConioIsRectEmpty(Rect) \
24 (((Rect)->Left > (Rect)->Right) || ((Rect)->Top > (Rect)->Bottom))
26 #define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
27 WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
29 #define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
30 MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
32 #define ConsoleUnicodeCharToAnsiChar(Console, dChar, sWChar) \
33 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
35 #define ConsoleAnsiCharToUnicodeChar(Console, dWChar, sChar) \
36 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
39 /* FUNCTIONS *****************************************************************/
42 ConioConsoleFromProcessData(PCSRSS_PROCESS_DATA ProcessData
, PCSRSS_CONSOLE
*Console
)
44 PCSRSS_CONSOLE ProcessConsole
;
46 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
47 ProcessConsole
= ProcessData
->Console
;
52 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
53 return STATUS_INVALID_HANDLE
;
56 InterlockedIncrement(&ProcessConsole
->ReferenceCount
);
57 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
58 EnterCriticalSection(&(ProcessConsole
->Lock
));
59 *Console
= ProcessConsole
;
61 return STATUS_SUCCESS
;
65 ConioConsoleCtrlEventTimeout(DWORD Event
, PCSRSS_PROCESS_DATA ProcessData
, DWORD Timeout
)
69 DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData
->ProcessId
);
71 if (ProcessData
->CtrlDispatcher
)
74 Thread
= CreateRemoteThread(ProcessData
->Process
, NULL
, 0,
75 (LPTHREAD_START_ROUTINE
) ProcessData
->CtrlDispatcher
,
76 UlongToPtr(Event
), 0, NULL
);
79 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
82 WaitForSingleObject(Thread
, Timeout
);
88 ConioConsoleCtrlEvent(DWORD Event
, PCSRSS_PROCESS_DATA ProcessData
)
90 ConioConsoleCtrlEventTimeout(Event
, ProcessData
, 0);
94 ConioCoordToPointer(PCSRSS_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
96 return &Buff
->Buffer
[2 * (((Y
+ Buff
->VirtualY
) % Buff
->MaxY
) * Buff
->MaxX
+ X
)];
100 ClearLineBuffer(PCSRSS_SCREEN_BUFFER Buff
)
102 PBYTE Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CurrentY
);
105 for (Pos
= 0; Pos
< Buff
->MaxX
; Pos
++)
109 *Ptr
++ = Buff
->DefaultAttrib
;
113 static NTSTATUS FASTCALL
114 CsrInitConsoleScreenBuffer(PCSRSS_CONSOLE Console
,
115 PCSRSS_SCREEN_BUFFER Buffer
)
117 DPRINT("CsrInitConsoleScreenBuffer Size X %d Size Y %d\n", Buffer
->MaxX
, Buffer
->MaxY
);
119 Buffer
->Header
.Type
= CONIO_SCREEN_BUFFER_MAGIC
;
120 Buffer
->Header
.Console
= Console
;
121 Buffer
->Header
.HandleCount
= 0;
124 Buffer
->VirtualY
= 0;
125 Buffer
->Buffer
= HeapAlloc(Win32CsrApiHeap
, HEAP_ZERO_MEMORY
, Buffer
->MaxX
* Buffer
->MaxY
* 2);
126 if (NULL
== Buffer
->Buffer
)
128 return STATUS_INSUFFICIENT_RESOURCES
;
130 ConioInitScreenBuffer(Console
, Buffer
);
131 /* initialize buffer to be empty with default attributes */
132 for (Buffer
->CurrentY
= 0 ; Buffer
->CurrentY
< Buffer
->MaxY
; Buffer
->CurrentY
++)
134 ClearLineBuffer(Buffer
);
136 Buffer
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
137 Buffer
->CurrentX
= 0;
138 Buffer
->CurrentY
= 0;
140 InsertHeadList(&Console
->BufferList
, &Buffer
->ListEntry
);
141 return STATUS_SUCCESS
;
144 static NTSTATUS WINAPI
145 CsrInitConsole(PCSRSS_CONSOLE Console
, BOOL Visible
)
148 SECURITY_ATTRIBUTES SecurityAttributes
;
149 PCSRSS_SCREEN_BUFFER NewBuffer
;
152 Console
->Title
.MaximumLength
= Console
->Title
.Length
= 0;
153 Console
->Title
.Buffer
= NULL
;
156 RtlCreateUnicodeString(&Console
->Title
, L
"Command Prompt");
158 Console
->ReferenceCount
= 0;
159 Console
->WaitingChars
= 0;
160 Console
->WaitingLines
= 0;
161 Console
->EchoCount
= 0;
162 Console
->Header
.Type
= CONIO_CONSOLE_MAGIC
;
163 Console
->Header
.Console
= Console
;
164 Console
->Mode
= ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
| ENABLE_PROCESSED_INPUT
| ENABLE_MOUSE_INPUT
;
165 Console
->EarlyReturn
= FALSE
;
166 InitializeListHead(&Console
->BufferList
);
167 Console
->ActiveBuffer
= NULL
;
168 InitializeListHead(&Console
->InputEvents
);
169 Console
->CodePage
= GetOEMCP();
170 Console
->OutputCodePage
= GetOEMCP();
172 SecurityAttributes
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
173 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
174 SecurityAttributes
.bInheritHandle
= TRUE
;
176 Console
->ActiveEvent
= CreateEventW(&SecurityAttributes
, TRUE
, FALSE
, NULL
);
177 if (NULL
== Console
->ActiveEvent
)
179 RtlFreeUnicodeString(&Console
->Title
);
180 return STATUS_UNSUCCESSFUL
;
182 Console
->PrivateData
= NULL
;
183 InitializeCriticalSection(&Console
->Lock
);
185 GuiMode
= DtbgIsDesktopVisible();
187 /* allocate console screen buffer */
188 NewBuffer
= HeapAlloc(Win32CsrApiHeap
, HEAP_ZERO_MEMORY
, sizeof(CSRSS_SCREEN_BUFFER
));
189 if (NULL
== NewBuffer
)
191 RtlFreeUnicodeString(&Console
->Title
);
192 DeleteCriticalSection(&Console
->Lock
);
193 CloseHandle(Console
->ActiveEvent
);
194 return STATUS_INSUFFICIENT_RESOURCES
;
196 /* init screen buffer with defaults */
197 NewBuffer
->CursorInfo
.bVisible
= TRUE
;
198 NewBuffer
->CursorInfo
.dwSize
= CSR_DEFAULT_CURSOR_SIZE
;
199 /* make console active, and insert into console list */
200 Console
->ActiveBuffer
= (PCSRSS_SCREEN_BUFFER
) NewBuffer
;
204 Status
= TuiInitConsole(Console
);
205 if (! NT_SUCCESS(Status
))
207 DPRINT1("Failed to open text-mode console, switching to gui-mode\n");
213 Status
= GuiInitConsole(Console
, Visible
);
214 if (! NT_SUCCESS(Status
))
216 HeapFree(Win32CsrApiHeap
,0, NewBuffer
);
217 RtlFreeUnicodeString(&Console
->Title
);
218 DeleteCriticalSection(&Console
->Lock
);
219 CloseHandle(Console
->ActiveEvent
);
220 DPRINT1("GuiInitConsole: failed\n");
225 Status
= CsrInitConsoleScreenBuffer(Console
, NewBuffer
);
226 if (! NT_SUCCESS(Status
))
228 ConioCleanupConsole(Console
);
229 RtlFreeUnicodeString(&Console
->Title
);
230 DeleteCriticalSection(&Console
->Lock
);
231 CloseHandle(Console
->ActiveEvent
);
232 HeapFree(Win32CsrApiHeap
, 0, NewBuffer
);
233 DPRINT1("CsrInitConsoleScreenBuffer: failed\n");
237 /* copy buffer contents to screen */
238 ConioDrawConsole(Console
);
240 return STATUS_SUCCESS
;
244 CSR_API(CsrAllocConsole
)
246 PCSRSS_CONSOLE Console
;
247 NTSTATUS Status
= STATUS_SUCCESS
;
248 BOOLEAN NewConsole
= FALSE
;
250 DPRINT("CsrAllocConsole\n");
252 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
253 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
255 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
256 if (ProcessData
->Console
)
258 DPRINT1("Process already has a console\n");
259 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
260 return STATUS_INVALID_PARAMETER
;
263 /* If we don't need a console, then get out of here */
264 if (!Request
->Data
.AllocConsoleRequest
.ConsoleNeeded
)
266 DPRINT("No console needed\n");
267 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
268 return STATUS_SUCCESS
;
271 /* If we already have one, then don't create a new one... */
272 if (!Request
->Data
.AllocConsoleRequest
.Console
||
273 Request
->Data
.AllocConsoleRequest
.Console
!= ProcessData
->ParentConsole
)
275 /* Allocate a console structure */
277 Console
= HeapAlloc(Win32CsrApiHeap
, HEAP_ZERO_MEMORY
, sizeof(CSRSS_CONSOLE
));
280 DPRINT1("Not enough memory for console\n");
281 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
282 return STATUS_NO_MEMORY
;
284 /* initialize list head */
285 InitializeListHead(&Console
->ProcessList
);
286 /* insert process data required for GUI initialization */
287 InsertHeadList(&Console
->ProcessList
, &ProcessData
->ProcessEntry
);
288 /* Initialize the Console */
289 Status
= CsrInitConsole(Console
, Request
->Data
.AllocConsoleRequest
.Visible
);
290 if (!NT_SUCCESS(Status
))
292 DPRINT1("Console init failed\n");
293 HeapFree(Win32CsrApiHeap
, 0, Console
);
294 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
300 /* Reuse our current console */
301 Console
= Request
->Data
.AllocConsoleRequest
.Console
;
304 /* Set the Process Console */
305 ProcessData
->Console
= Console
;
307 /* Return it to the caller */
308 Request
->Data
.AllocConsoleRequest
.Console
= Console
;
310 /* Add a reference count because the process is tied to the console */
311 _InterlockedIncrement(&Console
->ReferenceCount
);
313 if (NewConsole
|| !ProcessData
->bInheritHandles
)
315 /* Insert the Objects */
316 Status
= Win32CsrInsertObject(ProcessData
,
317 &Request
->Data
.AllocConsoleRequest
.InputHandle
,
319 GENERIC_READ
| GENERIC_WRITE
,
321 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
322 if (! NT_SUCCESS(Status
))
324 DPRINT1("Failed to insert object\n");
325 ConioDeleteConsole((Object_t
*) Console
);
326 ProcessData
->Console
= 0;
327 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
331 Status
= Win32CsrInsertObject(ProcessData
,
332 &Request
->Data
.AllocConsoleRequest
.OutputHandle
,
333 &Console
->ActiveBuffer
->Header
,
334 GENERIC_READ
| GENERIC_WRITE
,
336 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
337 if (!NT_SUCCESS(Status
))
339 DPRINT1("Failed to insert object\n");
340 ConioDeleteConsole((Object_t
*) Console
);
341 Win32CsrReleaseObject(ProcessData
,
342 Request
->Data
.AllocConsoleRequest
.InputHandle
);
343 ProcessData
->Console
= 0;
344 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
349 /* Duplicate the Event */
350 if (!DuplicateHandle(GetCurrentProcess(),
351 ProcessData
->Console
->ActiveEvent
,
352 ProcessData
->Process
,
353 &ProcessData
->ConsoleEvent
,
358 DPRINT1("DuplicateHandle() failed: %d\n", GetLastError
);
359 ConioDeleteConsole((Object_t
*) Console
);
360 if (NewConsole
|| !ProcessData
->bInheritHandles
)
362 Win32CsrReleaseObject(ProcessData
,
363 Request
->Data
.AllocConsoleRequest
.OutputHandle
);
364 Win32CsrReleaseObject(ProcessData
,
365 Request
->Data
.AllocConsoleRequest
.InputHandle
);
367 ProcessData
->Console
= 0;
368 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
372 /* Set the Ctrl Dispatcher */
373 ProcessData
->CtrlDispatcher
= Request
->Data
.AllocConsoleRequest
.CtrlDispatcher
;
374 DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData
->CtrlDispatcher
);
378 /* Insert into the list if it has not been added */
379 InsertHeadList(&ProcessData
->Console
->ProcessList
, &ProcessData
->ProcessEntry
);
382 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
383 return STATUS_SUCCESS
;
386 CSR_API(CsrFreeConsole
)
388 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
389 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
391 return Win32CsrReleaseConsole(ProcessData
);
395 ConioNextLine(PCSRSS_SCREEN_BUFFER Buff
, SMALL_RECT
*UpdateRect
, UINT
*ScrolledLines
)
397 /* If we hit bottom, slide the viewable screen */
398 if (++Buff
->CurrentY
== Buff
->MaxY
)
401 if (++Buff
->VirtualY
== Buff
->MaxY
)
406 ClearLineBuffer(Buff
);
407 if (UpdateRect
->Top
!= 0)
412 UpdateRect
->Left
= 0;
413 UpdateRect
->Right
= Buff
->MaxX
- 1;
414 UpdateRect
->Bottom
= Buff
->CurrentY
;
417 static NTSTATUS FASTCALL
418 ConioWriteConsole(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
,
419 CHAR
*Buffer
, DWORD Length
, BOOL Attrib
)
423 SMALL_RECT UpdateRect
;
424 LONG CursorStartX
, CursorStartY
;
427 CursorStartX
= Buff
->CurrentX
;
428 CursorStartY
= Buff
->CurrentY
;
429 UpdateRect
.Left
= Buff
->MaxX
;
430 UpdateRect
.Top
= Buff
->CurrentY
;
431 UpdateRect
.Right
= -1;
432 UpdateRect
.Bottom
= Buff
->CurrentY
;
435 for (i
= 0; i
< Length
; i
++)
437 if (Buff
->Mode
& ENABLE_PROCESSED_OUTPUT
)
440 if (Buffer
[i
] == '\n')
443 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
447 else if (Buffer
[i
] == '\b')
449 /* Only handle BS if we're not on the first pos of the first line */
450 if (0 != Buff
->CurrentX
|| 0 != Buff
->CurrentY
)
452 if (0 == Buff
->CurrentX
)
454 /* slide virtual position up */
455 Buff
->CurrentX
= Buff
->MaxX
- 1;
457 UpdateRect
.Top
= min(UpdateRect
.Top
, (LONG
)Buff
->CurrentY
);
463 Ptr
= ConioCoordToPointer(Buff
, Buff
->CurrentX
, Buff
->CurrentY
);
465 Ptr
[1] = Buff
->DefaultAttrib
;
466 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
) Buff
->CurrentX
);
467 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
) Buff
->CurrentX
);
472 else if (Buffer
[i
] == '\r')
475 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
) Buff
->CurrentX
);
476 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
) Buff
->CurrentX
);
480 else if (Buffer
[i
] == '\t')
484 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
)Buff
->CurrentX
);
485 EndX
= (Buff
->CurrentX
+ 8) & ~7;
486 if (EndX
> Buff
->MaxX
)
490 Ptr
= ConioCoordToPointer(Buff
, Buff
->CurrentX
, Buff
->CurrentY
);
491 while (Buff
->CurrentX
< EndX
)
494 *Ptr
++ = Buff
->DefaultAttrib
;
497 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
) Buff
->CurrentX
- 1);
498 if (Buff
->CurrentX
== Buff
->MaxX
)
500 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
503 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
513 UpdateRect
.Left
= min(UpdateRect
.Left
, (LONG
)Buff
->CurrentX
);
514 UpdateRect
.Right
= max(UpdateRect
.Right
, (LONG
) Buff
->CurrentX
);
515 Ptr
= ConioCoordToPointer(Buff
, Buff
->CurrentX
, Buff
->CurrentY
);
519 Ptr
[1] = Buff
->DefaultAttrib
;
522 if (Buff
->CurrentX
== Buff
->MaxX
)
524 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
527 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
531 Buff
->CurrentX
= CursorStartX
;
536 if (! ConioIsRectEmpty(&UpdateRect
) && Buff
== Console
->ActiveBuffer
)
538 ConioWriteStream(Console
, &UpdateRect
, CursorStartX
, CursorStartY
, ScrolledLines
,
542 return STATUS_SUCCESS
;
545 CSR_API(CsrReadConsole
)
547 PLIST_ENTRY CurrentEntry
;
550 PWCHAR UnicodeBuffer
;
552 ULONG nNumberOfCharsToRead
, CharSize
;
553 PCSRSS_CONSOLE Console
;
556 DPRINT("CsrReadConsole\n");
558 CharSize
= (Request
->Data
.ReadConsoleRequest
.Unicode
? sizeof(WCHAR
) : sizeof(CHAR
));
560 /* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
561 nNumberOfCharsToRead
= min(Request
->Data
.ReadConsoleRequest
.NrCharactersToRead
, CSRSS_MAX_READ_CONSOLE
/ CharSize
);
562 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
563 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
565 Buffer
= Request
->Data
.ReadConsoleRequest
.Buffer
;
566 UnicodeBuffer
= (PWCHAR
)Buffer
;
567 Status
= ConioLockConsole(ProcessData
, Request
->Data
.ReadConsoleRequest
.ConsoleHandle
,
568 &Console
, GENERIC_READ
);
569 if (! NT_SUCCESS(Status
))
573 Request
->Data
.ReadConsoleRequest
.EventHandle
= ProcessData
->ConsoleEvent
;
574 for (i
= 0; i
< nNumberOfCharsToRead
&& Console
->InputEvents
.Flink
!= &Console
->InputEvents
; i
++)
576 /* remove input event from queue */
577 CurrentEntry
= RemoveHeadList(&Console
->InputEvents
);
578 if (IsListEmpty(&Console
->InputEvents
))
580 ResetEvent(Console
->ActiveEvent
);
582 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
584 /* only pay attention to valid ascii chars, on key down */
585 if (KEY_EVENT
== Input
->InputEvent
.EventType
586 && Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
587 && Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
!= '\0')
590 * backspace handling - if we are in charge of echoing it then we handle it here
591 * otherwise we treat it like a normal char.
593 if ('\b' == Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
&& 0
594 != (Console
->Mode
& ENABLE_ECHO_INPUT
))
596 /* echo if it has not already been done, and either we or the client has chars to be deleted */
598 && (0 != i
|| Request
->Data
.ReadConsoleRequest
.nCharsCanBeDeleted
))
600 ConioWriteConsole(Console
, Console
->ActiveBuffer
,
601 &Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
605 i
-= 2; /* if we already have something to return, just back it up by 2 */
608 { /* otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer */
609 Console
->WaitingChars
--;
610 ConioUnlockConsole(Console
);
611 HeapFree(Win32CsrApiHeap
, 0, Input
);
612 Request
->Data
.ReadConsoleRequest
.NrCharactersRead
= 0;
613 return STATUS_NOTIFY_CLEANUP
;
616 Request
->Data
.ReadConsoleRequest
.nCharsCanBeDeleted
--;
617 Input
->Echoed
= TRUE
; /* mark as echoed so we don't echo it below */
619 /* do not copy backspace to buffer */
622 if(Request
->Data
.ReadConsoleRequest
.Unicode
)
623 ConsoleInputAnsiCharToUnicodeChar(Console
, &UnicodeBuffer
[i
], &Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
);
625 Buffer
[i
] = Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
;
627 /* echo to screen if enabled and we did not already echo the char */
628 if (0 != (Console
->Mode
& ENABLE_ECHO_INPUT
)
630 && '\r' != Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
632 ConioWriteConsole(Console
, Console
->ActiveBuffer
,
633 &Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
, 1, TRUE
);
640 Console
->WaitingChars
--;
641 HeapFree(Win32CsrApiHeap
, 0, Input
);
643 Request
->Data
.ReadConsoleRequest
.NrCharactersRead
= i
;
646 Status
= STATUS_PENDING
; /* we didn't read anything */
648 else if (0 != (Console
->Mode
& ENABLE_LINE_INPUT
))
650 if (0 == Console
->WaitingLines
||
651 (Request
->Data
.ReadConsoleRequest
.Unicode
? (L
'\n' != UnicodeBuffer
[i
- 1]) : ('\n' != Buffer
[i
- 1])))
653 Status
= STATUS_PENDING
; /* line buffered, didn't get a complete line */
657 Console
->WaitingLines
--;
658 Status
= STATUS_SUCCESS
; /* line buffered, did get a complete line */
663 Status
= STATUS_SUCCESS
; /* not line buffered, did read something */
666 if (Status
== STATUS_PENDING
)
668 Console
->EchoCount
= nNumberOfCharsToRead
- i
;
672 Console
->EchoCount
= 0; /* if the client is no longer waiting on input, do not echo */
675 ConioUnlockConsole(Console
);
677 if (CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE
) + i
* CharSize
> sizeof(CSR_API_MESSAGE
))
679 Request
->Header
.u1
.s1
.TotalLength
= CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE
) + i
* CharSize
;
680 Request
->Header
.u1
.s1
.DataLength
= Request
->Header
.u1
.s1
.TotalLength
- sizeof(PORT_MESSAGE
);
686 __inline BOOLEAN
ConioGetIntersection(
687 SMALL_RECT
*Intersection
,
691 if (ConioIsRectEmpty(Rect1
) ||
692 (ConioIsRectEmpty(Rect2
)) ||
693 (Rect1
->Top
> Rect2
->Bottom
) ||
694 (Rect1
->Left
> Rect2
->Right
) ||
695 (Rect1
->Bottom
< Rect2
->Top
) ||
696 (Rect1
->Right
< Rect2
->Left
))
698 /* The rectangles do not intersect */
699 ConioInitRect(Intersection
, 0, -1, 0, -1);
703 ConioInitRect(Intersection
,
704 max(Rect1
->Top
, Rect2
->Top
),
705 max(Rect1
->Left
, Rect2
->Left
),
706 min(Rect1
->Bottom
, Rect2
->Bottom
),
707 min(Rect1
->Right
, Rect2
->Right
));
712 __inline BOOLEAN
ConioGetUnion(
717 if (ConioIsRectEmpty(Rect1
))
719 if (ConioIsRectEmpty(Rect2
))
721 ConioInitRect(Union
, 0, -1, 0, -1);
729 else if (ConioIsRectEmpty(Rect2
))
736 min(Rect1
->Top
, Rect2
->Top
),
737 min(Rect1
->Left
, Rect2
->Left
),
738 max(Rect1
->Bottom
, Rect2
->Bottom
),
739 max(Rect1
->Right
, Rect2
->Right
));
745 /* Move from one rectangle to another. We must be careful about the order that
746 * this is done, to avoid overwriting parts of the source before they are moved. */
748 ConioMoveRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer
,
749 SMALL_RECT
*SrcRegion
,
750 SMALL_RECT
*DstRegion
,
751 SMALL_RECT
*ClipRegion
,
754 int Width
= ConioRectWidth(SrcRegion
);
755 int Height
= ConioRectHeight(SrcRegion
);
766 /* Moving down: work from bottom up */
767 SY
= SrcRegion
->Bottom
;
768 DY
= DstRegion
->Bottom
;
771 for (i
= 0; i
< Height
; i
++)
773 PWORD SRow
= (PWORD
)ConioCoordToPointer(ScreenBuffer
, 0, SY
);
774 PWORD DRow
= (PWORD
)ConioCoordToPointer(ScreenBuffer
, 0, DY
);
776 SX
= SrcRegion
->Left
;
777 DX
= DstRegion
->Left
;
781 /* Moving right: work from right to left */
782 SX
= SrcRegion
->Right
;
783 DX
= DstRegion
->Right
;
786 for (j
= 0; j
< Width
; j
++)
788 WORD Cell
= SRow
[SX
];
789 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
790 && SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
794 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
795 && DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
808 ConioInputEventToAnsi(PCSRSS_CONSOLE Console
, PINPUT_RECORD InputEvent
)
810 if (InputEvent
->EventType
== KEY_EVENT
)
812 WCHAR UnicodeChar
= InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
;
813 InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
= 0;
814 ConsoleInputUnicodeCharToAnsiChar(Console
,
815 &InputEvent
->Event
.KeyEvent
.uChar
.AsciiChar
,
820 CSR_API(CsrWriteConsole
)
824 PCSRSS_SCREEN_BUFFER Buff
;
825 PCSRSS_CONSOLE Console
;
828 ULONG CharSize
= (Request
->Data
.WriteConsoleRequest
.Unicode
? sizeof(WCHAR
) : sizeof(CHAR
));
830 DPRINT("CsrWriteConsole\n");
832 if (Request
->Header
.u1
.s1
.TotalLength
833 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE
)
834 + (Request
->Data
.WriteConsoleRequest
.NrCharactersToWrite
* CharSize
))
836 DPRINT1("Invalid request size\n");
837 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
838 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
839 return STATUS_INVALID_PARAMETER
;
842 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
843 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
845 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.WriteConsoleRequest
.ConsoleHandle
, &Buff
, GENERIC_WRITE
);
846 if (! NT_SUCCESS(Status
))
850 Console
= Buff
->Header
.Console
;
852 if (Console
->UnpauseEvent
)
854 Status
= NtDuplicateObject(GetCurrentProcess(), Console
->UnpauseEvent
,
855 ProcessData
->Process
, &Request
->Data
.WriteConsoleRequest
.UnpauseEvent
,
857 ConioUnlockScreenBuffer(Buff
);
858 return NT_SUCCESS(Status
) ? STATUS_PENDING
: Status
;
861 if(Request
->Data
.WriteConsoleRequest
.Unicode
)
863 Length
= WideCharToMultiByte(Console
->OutputCodePage
, 0,
864 (PWCHAR
)Request
->Data
.WriteConsoleRequest
.Buffer
,
865 Request
->Data
.WriteConsoleRequest
.NrCharactersToWrite
,
866 NULL
, 0, NULL
, NULL
);
867 Buffer
= RtlAllocateHeap(GetProcessHeap(), 0, Length
);
870 WideCharToMultiByte(Console
->OutputCodePage
, 0,
871 (PWCHAR
)Request
->Data
.WriteConsoleRequest
.Buffer
,
872 Request
->Data
.WriteConsoleRequest
.NrCharactersToWrite
,
873 Buffer
, Length
, NULL
, NULL
);
877 Status
= STATUS_NO_MEMORY
;
882 Buffer
= (PCHAR
)Request
->Data
.WriteConsoleRequest
.Buffer
;
887 if (NT_SUCCESS(Status
))
889 Status
= ConioWriteConsole(Console
, Buff
, Buffer
,
890 Request
->Data
.WriteConsoleRequest
.NrCharactersToWrite
, TRUE
);
891 if (NT_SUCCESS(Status
))
893 Written
= Request
->Data
.WriteConsoleRequest
.NrCharactersToWrite
;
896 if (Request
->Data
.WriteConsoleRequest
.Unicode
)
898 RtlFreeHeap(GetProcessHeap(), 0, Buffer
);
901 ConioUnlockScreenBuffer(Buff
);
903 Request
->Data
.WriteConsoleRequest
.NrCharactersWritten
= Written
;
909 ConioDeleteScreenBuffer(PCSRSS_SCREEN_BUFFER Buffer
)
911 PCSRSS_CONSOLE Console
= Buffer
->Header
.Console
;
913 RemoveEntryList(&Buffer
->ListEntry
);
914 if (Buffer
== Console
->ActiveBuffer
)
916 /* Deleted active buffer; switch to most recently created */
917 Console
->ActiveBuffer
= NULL
;
918 if (!IsListEmpty(&Console
->BufferList
))
920 Console
->ActiveBuffer
= CONTAINING_RECORD(Console
->BufferList
.Flink
, CSRSS_SCREEN_BUFFER
, ListEntry
);
921 ConioDrawConsole(Console
);
925 HeapFree(Win32CsrApiHeap
, 0, Buffer
->Buffer
);
926 HeapFree(Win32CsrApiHeap
, 0, Buffer
);
930 ConioDrawConsole(PCSRSS_CONSOLE Console
)
934 ConioInitRect(&Region
, 0, 0, Console
->Size
.Y
- 1, Console
->Size
.X
- 1);
936 ConioDrawRegion(Console
, &Region
);
941 ConioDeleteConsole(Object_t
*Object
)
943 PCSRSS_CONSOLE Console
= (PCSRSS_CONSOLE
) Object
;
946 DPRINT("ConioDeleteConsole\n");
948 /* Drain input event queue */
949 while (Console
->InputEvents
.Flink
!= &Console
->InputEvents
)
951 Event
= (ConsoleInput
*) Console
->InputEvents
.Flink
;
952 Console
->InputEvents
.Flink
= Console
->InputEvents
.Flink
->Flink
;
953 Console
->InputEvents
.Flink
->Flink
->Blink
= &Console
->InputEvents
;
954 HeapFree(Win32CsrApiHeap
, 0, Event
);
957 ConioCleanupConsole(Console
);
958 ConioDeleteScreenBuffer(Console
->ActiveBuffer
);
959 if (!IsListEmpty(&Console
->BufferList
))
961 DPRINT1("BUG: screen buffer list not empty\n");
964 CloseHandle(Console
->ActiveEvent
);
965 if (Console
->UnpauseEvent
) CloseHandle(Console
->UnpauseEvent
);
966 DeleteCriticalSection(&Console
->Lock
);
967 RtlFreeUnicodeString(&Console
->Title
);
968 IntDeleteAllAliases(Console
->Aliases
);
969 HeapFree(Win32CsrApiHeap
, 0, Console
);
973 CsrInitConsoleSupport(VOID
)
975 DPRINT("CSR: CsrInitConsoleSupport()\n");
977 /* Should call LoadKeyboardLayout */
981 ConioPause(PCSRSS_CONSOLE Console
, UINT Flags
)
983 Console
->PauseFlags
|= Flags
;
984 if (!Console
->UnpauseEvent
)
985 Console
->UnpauseEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
989 ConioUnpause(PCSRSS_CONSOLE Console
, UINT Flags
)
991 Console
->PauseFlags
&= ~Flags
;
992 if (Console
->PauseFlags
== 0 && Console
->UnpauseEvent
)
994 SetEvent(Console
->UnpauseEvent
);
995 CloseHandle(Console
->UnpauseEvent
);
996 Console
->UnpauseEvent
= NULL
;
1000 static VOID FASTCALL
1001 ConioProcessChar(PCSRSS_CONSOLE Console
,
1002 ConsoleInput
*KeyEventRecord
)
1005 ConsoleInput
*TempInput
;
1007 if (KeyEventRecord
->InputEvent
.EventType
== KEY_EVENT
&&
1008 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
)
1010 WORD vk
= KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
;
1011 if (!(Console
->PauseFlags
& PAUSED_FROM_KEYBOARD
))
1013 DWORD cks
= KeyEventRecord
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
;
1014 if (Console
->Mode
& ENABLE_LINE_INPUT
&&
1015 (vk
== VK_PAUSE
|| (vk
== 'S' &&
1016 (cks
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) &&
1017 !(cks
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
)))))
1019 ConioPause(Console
, PAUSED_FROM_KEYBOARD
);
1020 HeapFree(Win32CsrApiHeap
, 0, KeyEventRecord
);
1026 if ((vk
< VK_SHIFT
|| vk
> VK_CAPITAL
) && vk
!= VK_LWIN
&&
1027 vk
!= VK_RWIN
&& vk
!= VK_NUMLOCK
&& vk
!= VK_SCROLL
)
1029 ConioUnpause(Console
, PAUSED_FROM_KEYBOARD
);
1030 HeapFree(Win32CsrApiHeap
, 0, KeyEventRecord
);
1036 if (0 != (Console
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
)))
1038 switch(KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
1041 /* first add the \r */
1042 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
1043 updown
= KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
;
1044 KeyEventRecord
->Echoed
= FALSE
;
1045 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
= VK_RETURN
;
1046 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\r';
1047 InsertTailList(&Console
->InputEvents
, &KeyEventRecord
->ListEntry
);
1048 Console
->WaitingChars
++;
1049 KeyEventRecord
= HeapAlloc(Win32CsrApiHeap
, 0, sizeof(ConsoleInput
));
1050 if (NULL
== KeyEventRecord
)
1052 DPRINT1("Failed to allocate KeyEventRecord\n");
1055 KeyEventRecord
->InputEvent
.EventType
= KEY_EVENT
;
1056 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
= updown
;
1057 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualKeyCode
= 0;
1058 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.wVirtualScanCode
= 0;
1059 KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
= '\n';
1060 KeyEventRecord
->Fake
= TRUE
;
1064 /* add event to the queue */
1065 InsertTailList(&Console
->InputEvents
, &KeyEventRecord
->ListEntry
);
1066 Console
->WaitingChars
++;
1067 /* if line input mode is enabled, only wake the client on enter key down */
1068 if (0 == (Console
->Mode
& ENABLE_LINE_INPUT
)
1069 || Console
->EarlyReturn
1070 || ('\n' == KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
1071 && KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
))
1073 if ('\n' == KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
1075 Console
->WaitingLines
++;
1078 KeyEventRecord
->Echoed
= FALSE
;
1079 if (0 != (Console
->Mode
& (ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
))
1080 && '\b' == KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
1081 && KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
)
1083 /* walk the input queue looking for a char to backspace */
1084 for (TempInput
= (ConsoleInput
*) Console
->InputEvents
.Blink
;
1085 TempInput
!= (ConsoleInput
*) &Console
->InputEvents
1086 && (KEY_EVENT
== TempInput
->InputEvent
.EventType
1087 || ! TempInput
->InputEvent
.Event
.KeyEvent
.bKeyDown
1088 || '\b' == TempInput
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
);
1089 TempInput
= (ConsoleInput
*) TempInput
->ListEntry
.Blink
)
1093 /* if we found one, delete it, otherwise, wake the client */
1094 if (TempInput
!= (ConsoleInput
*) &Console
->InputEvents
)
1096 /* delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue */
1097 RemoveEntryList(&TempInput
->ListEntry
);
1098 if (TempInput
->Echoed
)
1100 ConioWriteConsole(Console
, Console
->ActiveBuffer
,
1101 &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
,
1104 HeapFree(Win32CsrApiHeap
, 0, TempInput
);
1105 RemoveEntryList(&KeyEventRecord
->ListEntry
);
1106 HeapFree(Win32CsrApiHeap
, 0, KeyEventRecord
);
1107 Console
->WaitingChars
-= 2;
1113 /* echo chars if we are supposed to and client is waiting for some */
1114 if (0 != (Console
->Mode
& ENABLE_ECHO_INPUT
) && Console
->EchoCount
1115 && KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
1116 && KeyEventRecord
->InputEvent
.Event
.KeyEvent
.bKeyDown
1117 && '\r' != KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
1119 /* mark the char as already echoed */
1120 ConioWriteConsole(Console
, Console
->ActiveBuffer
,
1121 &KeyEventRecord
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
,
1123 Console
->EchoCount
--;
1124 KeyEventRecord
->Echoed
= TRUE
;
1128 /* Console->WaitingChars++; */
1129 SetEvent(Console
->ActiveEvent
);
1132 static DWORD FASTCALL
1133 ConioGetShiftState(PBYTE KeyState
)
1137 if (KeyState
[VK_CAPITAL
] & 1)
1138 ssOut
|= CAPSLOCK_ON
;
1140 if (KeyState
[VK_NUMLOCK
] & 1)
1141 ssOut
|= NUMLOCK_ON
;
1143 if (KeyState
[VK_SCROLL
] & 1)
1144 ssOut
|= SCROLLLOCK_ON
;
1146 if (KeyState
[VK_SHIFT
] & 0x80)
1147 ssOut
|= SHIFT_PRESSED
;
1149 if (KeyState
[VK_LCONTROL
] & 0x80)
1150 ssOut
|= LEFT_CTRL_PRESSED
;
1151 if (KeyState
[VK_RCONTROL
] & 0x80)
1152 ssOut
|= RIGHT_CTRL_PRESSED
;
1154 if (KeyState
[VK_LMENU
] & 0x80)
1155 ssOut
|= LEFT_ALT_PRESSED
;
1156 if (KeyState
[VK_RMENU
] & 0x80)
1157 ssOut
|= RIGHT_ALT_PRESSED
;
1163 ConioProcessKey(MSG
*msg
, PCSRSS_CONSOLE Console
, BOOL TextMode
)
1165 static BYTE KeyState
[256] = { 0 };
1166 /* MSDN mentions that you should use the last virtual key code received
1167 * when putting a virtual key identity to a WM_CHAR message since multiple
1168 * or translated keys may be involved. */
1169 static UINT LastVirtualKey
= 0;
1171 ConsoleInput
*ConInRec
;
1175 UINT VirtualKeyCode
;
1176 UINT VirtualScanCode
;
1179 ULONG ResultSize
= 0;
1182 VirtualScanCode
= (msg
->lParam
>> 16) & 0xff;
1183 Down
= msg
->message
== WM_KEYDOWN
|| msg
->message
== WM_CHAR
||
1184 msg
->message
== WM_SYSKEYDOWN
|| msg
->message
== WM_SYSCHAR
;
1186 GetKeyboardState(KeyState
);
1187 ShiftState
= ConioGetShiftState(KeyState
);
1189 if (msg
->message
== WM_CHAR
|| msg
->message
== WM_SYSCHAR
)
1191 VirtualKeyCode
= LastVirtualKey
;
1192 UnicodeChar
= msg
->wParam
;
1199 VirtualKeyCode
= msg
->wParam
;
1200 RetChars
= ToUnicodeEx(VirtualKeyCode
,
1207 UnicodeChar
= (1 == RetChars
? Chars
[0] : 0);
1210 if (0 == ResultSize
)
1215 er
.EventType
= KEY_EVENT
;
1216 er
.Event
.KeyEvent
.bKeyDown
= Down
;
1217 er
.Event
.KeyEvent
.wRepeatCount
= RepeatCount
;
1218 er
.Event
.KeyEvent
.uChar
.UnicodeChar
= UnicodeChar
;
1219 er
.Event
.KeyEvent
.dwControlKeyState
= ShiftState
;
1220 er
.Event
.KeyEvent
.wVirtualKeyCode
= VirtualKeyCode
;
1221 er
.Event
.KeyEvent
.wVirtualScanCode
= VirtualScanCode
;
1225 if (0 != (ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
1226 && VK_TAB
== VirtualKeyCode
)
1230 TuiSwapConsole(ShiftState
& SHIFT_PRESSED
? -1 : 1);
1235 else if (VK_MENU
== VirtualKeyCode
&& ! Down
)
1237 if (TuiSwapConsole(0))
1244 if (NULL
== Console
)
1246 DPRINT1("No Active Console!\n");
1250 ConInRec
= HeapAlloc(Win32CsrApiHeap
, 0, sizeof(ConsoleInput
));
1252 if (NULL
== ConInRec
)
1257 ConInRec
->InputEvent
= er
;
1258 ConInRec
->Fake
= UnicodeChar
&&
1259 (msg
->message
!= WM_CHAR
&& msg
->message
!= WM_SYSCHAR
&&
1260 msg
->message
!= WM_KEYUP
&& msg
->message
!= WM_SYSKEYUP
);
1261 ConInRec
->NotChar
= (msg
->message
!= WM_CHAR
&& msg
->message
!= WM_SYSCHAR
);
1262 ConInRec
->Echoed
= FALSE
;
1263 if (ConInRec
->NotChar
)
1264 LastVirtualKey
= msg
->wParam
;
1266 DPRINT ("csrss: %s %s %s %s %02x %02x '%c' %04x\n",
1267 Down
? "down" : "up ",
1268 (msg
->message
== WM_CHAR
|| msg
->message
== WM_SYSCHAR
) ?
1270 ConInRec
->Fake
? "fake" : "real",
1271 ConInRec
->NotChar
? "notc" : "char",
1274 (AsciiChar
>= ' ') ? AsciiChar
: '.',
1277 if (ConInRec
->Fake
&& ConInRec
->NotChar
)
1279 HeapFree(Win32CsrApiHeap
, 0, ConInRec
);
1283 /* process Ctrl-C and Ctrl-Break */
1284 if (Console
->Mode
& ENABLE_PROCESSED_INPUT
&&
1285 er
.Event
.KeyEvent
.bKeyDown
&&
1286 ((er
.Event
.KeyEvent
.wVirtualKeyCode
== VK_PAUSE
) ||
1287 (er
.Event
.KeyEvent
.wVirtualKeyCode
== 'C')) &&
1288 (er
.Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)))
1290 PCSRSS_PROCESS_DATA current
;
1291 PLIST_ENTRY current_entry
;
1292 DPRINT1("Console_Api Ctrl-C\n");
1293 current_entry
= Console
->ProcessList
.Flink
;
1294 while (current_entry
!= &Console
->ProcessList
)
1296 current
= CONTAINING_RECORD(current_entry
, CSRSS_PROCESS_DATA
, ProcessEntry
);
1297 current_entry
= current_entry
->Flink
;
1298 ConioConsoleCtrlEvent((DWORD
)CTRL_C_EVENT
, current
);
1300 HeapFree(Win32CsrApiHeap
, 0, ConInRec
);
1304 if (0 != (er
.Event
.KeyEvent
.dwControlKeyState
1305 & (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
1306 && (VK_UP
== er
.Event
.KeyEvent
.wVirtualKeyCode
1307 || VK_DOWN
== er
.Event
.KeyEvent
.wVirtualKeyCode
))
1309 if (er
.Event
.KeyEvent
.bKeyDown
)
1311 /* scroll up or down */
1312 if (VK_UP
== er
.Event
.KeyEvent
.wVirtualKeyCode
)
1314 /* only scroll up if there is room to scroll up into */
1315 if (Console
->ActiveBuffer
->CurrentY
!= Console
->ActiveBuffer
->MaxY
- 1)
1317 Console
->ActiveBuffer
->VirtualY
= (Console
->ActiveBuffer
->VirtualY
+
1318 Console
->ActiveBuffer
->MaxY
- 1) %
1319 Console
->ActiveBuffer
->MaxY
;
1320 Console
->ActiveBuffer
->CurrentY
++;
1325 /* only scroll down if there is room to scroll down into */
1326 if (Console
->ActiveBuffer
->CurrentY
!= 0)
1328 Console
->ActiveBuffer
->VirtualY
= (Console
->ActiveBuffer
->VirtualY
+ 1) %
1329 Console
->ActiveBuffer
->MaxY
;
1330 Console
->ActiveBuffer
->CurrentY
--;
1333 ConioDrawConsole(Console
);
1335 HeapFree(Win32CsrApiHeap
, 0, ConInRec
);
1338 /* FIXME - convert to ascii */
1339 ConioProcessChar(Console
, ConInRec
);
1342 CSR_API(CsrGetScreenBufferInfo
)
1345 PCSRSS_CONSOLE Console
;
1346 PCSRSS_SCREEN_BUFFER Buff
;
1347 PCONSOLE_SCREEN_BUFFER_INFO pInfo
;
1349 DPRINT("CsrGetScreenBufferInfo\n");
1351 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1352 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1354 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.ScreenBufferInfoRequest
.ConsoleHandle
, &Buff
, GENERIC_READ
);
1355 if (! NT_SUCCESS(Status
))
1359 Console
= Buff
->Header
.Console
;
1360 pInfo
= &Request
->Data
.ScreenBufferInfoRequest
.Info
;
1361 pInfo
->dwSize
.X
= Buff
->MaxX
;
1362 pInfo
->dwSize
.Y
= Buff
->MaxY
;
1363 pInfo
->dwCursorPosition
.X
= Buff
->CurrentX
;
1364 pInfo
->dwCursorPosition
.Y
= Buff
->CurrentY
;
1365 pInfo
->wAttributes
= Buff
->DefaultAttrib
;
1366 pInfo
->srWindow
.Left
= Buff
->ShowX
;
1367 pInfo
->srWindow
.Right
= Buff
->ShowX
+ Console
->Size
.X
- 1;
1368 pInfo
->srWindow
.Top
= Buff
->ShowY
;
1369 pInfo
->srWindow
.Bottom
= Buff
->ShowY
+ Console
->Size
.Y
- 1;
1370 pInfo
->dwMaximumWindowSize
.X
= Buff
->MaxX
;
1371 pInfo
->dwMaximumWindowSize
.Y
= Buff
->MaxY
;
1372 ConioUnlockScreenBuffer(Buff
);
1374 return STATUS_SUCCESS
;
1377 CSR_API(CsrSetCursor
)
1380 PCSRSS_CONSOLE Console
;
1381 PCSRSS_SCREEN_BUFFER Buff
;
1382 LONG OldCursorX
, OldCursorY
;
1383 LONG NewCursorX
, NewCursorY
;
1385 DPRINT("CsrSetCursor\n");
1387 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1388 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1390 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.SetCursorRequest
.ConsoleHandle
, &Buff
, GENERIC_WRITE
);
1391 if (! NT_SUCCESS(Status
))
1395 Console
= Buff
->Header
.Console
;
1397 NewCursorX
= Request
->Data
.SetCursorRequest
.Position
.X
;
1398 NewCursorY
= Request
->Data
.SetCursorRequest
.Position
.Y
;
1399 if (NewCursorX
< 0 || NewCursorX
>= Buff
->MaxX
||
1400 NewCursorY
< 0 || NewCursorY
>= Buff
->MaxY
)
1402 ConioUnlockScreenBuffer(Buff
);
1403 return STATUS_INVALID_PARAMETER
;
1405 OldCursorX
= Buff
->CurrentX
;
1406 OldCursorY
= Buff
->CurrentY
;
1407 Buff
->CurrentX
= NewCursorX
;
1408 Buff
->CurrentY
= NewCursorY
;
1409 if (Buff
== Console
->ActiveBuffer
)
1411 if (! ConioSetScreenInfo(Console
, Buff
, OldCursorX
, OldCursorY
))
1413 ConioUnlockScreenBuffer(Buff
);
1414 return STATUS_UNSUCCESSFUL
;
1418 ConioUnlockScreenBuffer(Buff
);
1420 return STATUS_SUCCESS
;
1423 static VOID FASTCALL
1424 ConioComputeUpdateRect(PCSRSS_SCREEN_BUFFER Buff
, SMALL_RECT
*UpdateRect
, COORD
*Start
, UINT Length
)
1426 if (Buff
->MaxX
<= Start
->X
+ Length
)
1428 UpdateRect
->Left
= 0;
1432 UpdateRect
->Left
= Start
->X
;
1434 if (Buff
->MaxX
<= Start
->X
+ Length
)
1436 UpdateRect
->Right
= Buff
->MaxX
- 1;
1440 UpdateRect
->Right
= Start
->X
+ Length
- 1;
1442 UpdateRect
->Top
= Start
->Y
;
1443 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->MaxX
;
1444 if (Buff
->MaxY
<= UpdateRect
->Bottom
)
1446 UpdateRect
->Bottom
= Buff
->MaxY
- 1;
1450 CSR_API(CsrWriteConsoleOutputChar
)
1453 PCHAR String
, tmpString
= NULL
;
1455 PCSRSS_CONSOLE Console
;
1456 PCSRSS_SCREEN_BUFFER Buff
;
1457 DWORD X
, Y
, Length
, CharSize
, Written
= 0;
1458 SMALL_RECT UpdateRect
;
1460 DPRINT("CsrWriteConsoleOutputChar\n");
1462 CharSize
= (Request
->Data
.WriteConsoleOutputCharRequest
.Unicode
? sizeof(WCHAR
) : sizeof(CHAR
));
1464 if (Request
->Header
.u1
.s1
.TotalLength
1465 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR
)
1466 + (Request
->Data
.WriteConsoleOutputCharRequest
.Length
* CharSize
))
1468 DPRINT1("Invalid request size\n");
1469 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1470 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1471 return STATUS_INVALID_PARAMETER
;
1474 Status
= ConioLockScreenBuffer(ProcessData
,
1475 Request
->Data
.WriteConsoleOutputCharRequest
.ConsoleHandle
,
1478 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1479 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1480 if (NT_SUCCESS(Status
))
1482 Console
= Buff
->Header
.Console
;
1483 if(Request
->Data
.WriteConsoleOutputCharRequest
.Unicode
)
1485 Length
= WideCharToMultiByte(Console
->OutputCodePage
, 0,
1486 (PWCHAR
)Request
->Data
.WriteConsoleOutputCharRequest
.String
,
1487 Request
->Data
.WriteConsoleOutputCharRequest
.Length
,
1488 NULL
, 0, NULL
, NULL
);
1489 tmpString
= String
= RtlAllocateHeap(GetProcessHeap(), 0, Length
);
1492 WideCharToMultiByte(Console
->OutputCodePage
, 0,
1493 (PWCHAR
)Request
->Data
.WriteConsoleOutputCharRequest
.String
,
1494 Request
->Data
.WriteConsoleOutputCharRequest
.Length
,
1495 String
, Length
, NULL
, NULL
);
1499 Status
= STATUS_NO_MEMORY
;
1504 String
= (PCHAR
)Request
->Data
.WriteConsoleOutputCharRequest
.String
;
1509 if (NT_SUCCESS(Status
))
1511 X
= Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.X
;
1512 Y
= (Request
->Data
.WriteConsoleOutputCharRequest
.Coord
.Y
+ Buff
->VirtualY
) % Buff
->MaxY
;
1513 Length
= Request
->Data
.WriteConsoleOutputCharRequest
.Length
;
1514 Buffer
= &Buff
->Buffer
[2 * (Y
* Buff
->MaxX
+ X
)];
1517 *Buffer
= *String
++;
1520 if (++X
== Buff
->MaxX
)
1522 if (++Y
== Buff
->MaxY
)
1525 Buffer
= Buff
->Buffer
;
1530 if (Buff
== Console
->ActiveBuffer
)
1532 ConioComputeUpdateRect(Buff
, &UpdateRect
, &Request
->Data
.WriteConsoleOutputCharRequest
.Coord
,
1533 Request
->Data
.WriteConsoleOutputCharRequest
.Length
);
1534 ConioDrawRegion(Console
, &UpdateRect
);
1537 Request
->Data
.WriteConsoleOutputCharRequest
.EndCoord
.X
= X
;
1538 Request
->Data
.WriteConsoleOutputCharRequest
.EndCoord
.Y
= (Y
+ Buff
->MaxY
- Buff
->VirtualY
) % Buff
->MaxY
;
1541 if (Request
->Data
.WriteConsoleRequest
.Unicode
)
1543 RtlFreeHeap(GetProcessHeap(), 0, tmpString
);
1546 ConioUnlockScreenBuffer(Buff
);
1548 Request
->Data
.WriteConsoleOutputCharRequest
.NrCharactersWritten
= Written
;
1552 CSR_API(CsrFillOutputChar
)
1555 PCSRSS_CONSOLE Console
;
1556 PCSRSS_SCREEN_BUFFER Buff
;
1557 DWORD X
, Y
, Length
, Written
= 0;
1560 SMALL_RECT UpdateRect
;
1562 DPRINT("CsrFillOutputChar\n");
1564 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1565 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1567 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.FillOutputRequest
.ConsoleHandle
, &Buff
, GENERIC_WRITE
);
1568 if (! NT_SUCCESS(Status
))
1572 Console
= Buff
->Header
.Console
;
1574 X
= Request
->Data
.FillOutputRequest
.Position
.X
;
1575 Y
= (Request
->Data
.FillOutputRequest
.Position
.Y
+ Buff
->VirtualY
) % Buff
->MaxY
;
1576 Buffer
= &Buff
->Buffer
[2 * (Y
* Buff
->MaxX
+ X
)];
1577 if(Request
->Data
.FillOutputRequest
.Unicode
)
1578 ConsoleUnicodeCharToAnsiChar(Console
, &Char
, &Request
->Data
.FillOutputRequest
.Char
.UnicodeChar
);
1580 Char
= Request
->Data
.FillOutputRequest
.Char
.AsciiChar
;
1581 Length
= Request
->Data
.FillOutputRequest
.Length
;
1587 if (++X
== Buff
->MaxX
)
1589 if (++Y
== Buff
->MaxY
)
1592 Buffer
= Buff
->Buffer
;
1598 if (Buff
== Console
->ActiveBuffer
)
1600 ConioComputeUpdateRect(Buff
, &UpdateRect
, &Request
->Data
.FillOutputRequest
.Position
,
1601 Request
->Data
.FillOutputRequest
.Length
);
1602 ConioDrawRegion(Console
, &UpdateRect
);
1605 ConioUnlockScreenBuffer(Buff
);
1606 Length
= Request
->Data
.FillOutputRequest
.Length
;
1607 Request
->Data
.FillOutputRequest
.NrCharactersWritten
= Length
;
1608 return STATUS_SUCCESS
;
1611 CSR_API(CsrReadInputEvent
)
1613 PLIST_ENTRY CurrentEntry
;
1614 PCSRSS_CONSOLE Console
;
1616 BOOLEAN Done
= FALSE
;
1617 ConsoleInput
*Input
;
1619 DPRINT("CsrReadInputEvent\n");
1621 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1622 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1623 Request
->Data
.ReadInputRequest
.Event
= ProcessData
->ConsoleEvent
;
1625 Status
= ConioLockConsole(ProcessData
, Request
->Data
.ReadInputRequest
.ConsoleHandle
, &Console
, GENERIC_READ
);
1626 if (! NT_SUCCESS(Status
))
1631 /* only get input if there is any */
1632 CurrentEntry
= Console
->InputEvents
.Flink
;
1633 while (CurrentEntry
!= &Console
->InputEvents
)
1635 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
1636 CurrentEntry
= CurrentEntry
->Flink
;
1638 if (Done
&& !Input
->Fake
)
1640 Request
->Data
.ReadInputRequest
.MoreEvents
= TRUE
;
1644 RemoveEntryList(&Input
->ListEntry
);
1646 if (!Done
&& !Input
->Fake
)
1648 Request
->Data
.ReadInputRequest
.Input
= Input
->InputEvent
;
1649 if (Request
->Data
.ReadInputRequest
.Unicode
== FALSE
)
1651 ConioInputEventToAnsi(Console
, &Request
->Data
.ReadInputRequest
.Input
);
1656 if (Input
->InputEvent
.EventType
== KEY_EVENT
)
1658 if (0 != (Console
->Mode
& ENABLE_LINE_INPUT
)
1659 && Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
1660 && '\r' == Input
->InputEvent
.Event
.KeyEvent
.uChar
.AsciiChar
)
1662 Console
->WaitingLines
--;
1664 Console
->WaitingChars
--;
1666 HeapFree(Win32CsrApiHeap
, 0, Input
);
1671 Status
= STATUS_SUCCESS
;
1672 Console
->EarlyReturn
= FALSE
;
1676 Status
= STATUS_PENDING
;
1677 Console
->EarlyReturn
= TRUE
; /* mark for early return */
1680 if (IsListEmpty(&Console
->InputEvents
))
1682 ResetEvent(Console
->ActiveEvent
);
1685 ConioUnlockConsole(Console
);
1690 CSR_API(CsrWriteConsoleOutputAttrib
)
1692 PCSRSS_CONSOLE Console
;
1693 PCSRSS_SCREEN_BUFFER Buff
;
1698 SMALL_RECT UpdateRect
;
1700 DPRINT("CsrWriteConsoleOutputAttrib\n");
1702 if (Request
->Header
.u1
.s1
.TotalLength
1703 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB
)
1704 + Request
->Data
.WriteConsoleOutputAttribRequest
.Length
* sizeof(WORD
))
1706 DPRINT1("Invalid request size\n");
1707 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1708 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1709 return STATUS_INVALID_PARAMETER
;
1712 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1713 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1715 Status
= ConioLockScreenBuffer(ProcessData
,
1716 Request
->Data
.WriteConsoleOutputAttribRequest
.ConsoleHandle
,
1719 if (! NT_SUCCESS(Status
))
1723 Console
= Buff
->Header
.Console
;
1725 X
= Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.X
;
1726 Y
= (Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
.Y
+ Buff
->VirtualY
) % Buff
->MaxY
;
1727 Length
= Request
->Data
.WriteConsoleOutputAttribRequest
.Length
;
1728 Buffer
= &Buff
->Buffer
[2 * (Y
* Buff
->MaxX
+ X
) + 1];
1729 Attribute
= Request
->Data
.WriteConsoleOutputAttribRequest
.Attribute
;
1732 *Buffer
= (UCHAR
)(*Attribute
++);
1734 if (++X
== Buff
->MaxX
)
1736 if (++Y
== Buff
->MaxY
)
1739 Buffer
= Buff
->Buffer
+ 1;
1745 if (Buff
== Console
->ActiveBuffer
)
1747 ConioComputeUpdateRect(Buff
, &UpdateRect
, &Request
->Data
.WriteConsoleOutputAttribRequest
.Coord
,
1748 Request
->Data
.WriteConsoleOutputAttribRequest
.Length
);
1749 ConioDrawRegion(Console
, &UpdateRect
);
1752 Request
->Data
.WriteConsoleOutputAttribRequest
.EndCoord
.X
= X
;
1753 Request
->Data
.WriteConsoleOutputAttribRequest
.EndCoord
.Y
= (Y
+ Buff
->MaxY
- Buff
->VirtualY
) % Buff
->MaxY
;
1755 ConioUnlockScreenBuffer(Buff
);
1757 return STATUS_SUCCESS
;
1760 CSR_API(CsrFillOutputAttrib
)
1762 PCSRSS_SCREEN_BUFFER Buff
;
1767 SMALL_RECT UpdateRect
;
1768 PCSRSS_CONSOLE Console
;
1770 DPRINT("CsrFillOutputAttrib\n");
1772 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1773 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1774 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.FillOutputAttribRequest
.ConsoleHandle
, &Buff
, GENERIC_WRITE
);
1775 if (! NT_SUCCESS(Status
))
1779 Console
= Buff
->Header
.Console
;
1781 X
= Request
->Data
.FillOutputAttribRequest
.Coord
.X
;
1782 Y
= (Request
->Data
.FillOutputAttribRequest
.Coord
.Y
+ Buff
->VirtualY
) % Buff
->MaxY
;
1783 Length
= Request
->Data
.FillOutputAttribRequest
.Length
;
1784 Attr
= Request
->Data
.FillOutputAttribRequest
.Attribute
;
1785 Buffer
= &Buff
->Buffer
[(Y
* Buff
->MaxX
* 2) + (X
* 2) + 1];
1790 if (++X
== Buff
->MaxX
)
1792 if (++Y
== Buff
->MaxY
)
1795 Buffer
= Buff
->Buffer
+ 1;
1801 if (Buff
== Console
->ActiveBuffer
)
1803 ConioComputeUpdateRect(Buff
, &UpdateRect
, &Request
->Data
.FillOutputAttribRequest
.Coord
,
1804 Request
->Data
.FillOutputAttribRequest
.Length
);
1805 ConioDrawRegion(Console
, &UpdateRect
);
1808 ConioUnlockScreenBuffer(Buff
);
1810 return STATUS_SUCCESS
;
1814 CSR_API(CsrGetCursorInfo
)
1816 PCSRSS_SCREEN_BUFFER Buff
;
1819 DPRINT("CsrGetCursorInfo\n");
1821 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1822 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1824 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.GetCursorInfoRequest
.ConsoleHandle
, &Buff
, GENERIC_READ
);
1825 if (! NT_SUCCESS(Status
))
1829 Request
->Data
.GetCursorInfoRequest
.Info
.bVisible
= Buff
->CursorInfo
.bVisible
;
1830 Request
->Data
.GetCursorInfoRequest
.Info
.dwSize
= Buff
->CursorInfo
.dwSize
;
1831 ConioUnlockScreenBuffer(Buff
);
1833 return STATUS_SUCCESS
;
1836 CSR_API(CsrSetCursorInfo
)
1838 PCSRSS_CONSOLE Console
;
1839 PCSRSS_SCREEN_BUFFER Buff
;
1844 DPRINT("CsrSetCursorInfo\n");
1846 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1847 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1849 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.SetCursorInfoRequest
.ConsoleHandle
, &Buff
, GENERIC_WRITE
);
1850 if (! NT_SUCCESS(Status
))
1854 Console
= Buff
->Header
.Console
;
1856 Size
= Request
->Data
.SetCursorInfoRequest
.Info
.dwSize
;
1857 Visible
= Request
->Data
.SetCursorInfoRequest
.Info
.bVisible
;
1867 if (Size
!= Buff
->CursorInfo
.dwSize
1868 || (Visible
&& ! Buff
->CursorInfo
.bVisible
) || (! Visible
&& Buff
->CursorInfo
.bVisible
))
1870 Buff
->CursorInfo
.dwSize
= Size
;
1871 Buff
->CursorInfo
.bVisible
= Visible
;
1873 if (! ConioSetCursorInfo(Console
, Buff
))
1875 ConioUnlockScreenBuffer(Buff
);
1876 return STATUS_UNSUCCESSFUL
;
1880 ConioUnlockScreenBuffer(Buff
);
1882 return STATUS_SUCCESS
;
1885 CSR_API(CsrSetTextAttrib
)
1888 PCSRSS_CONSOLE Console
;
1889 PCSRSS_SCREEN_BUFFER Buff
;
1891 DPRINT("CsrSetTextAttrib\n");
1893 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.SetCursorRequest
.ConsoleHandle
, &Buff
, GENERIC_WRITE
);
1894 if (! NT_SUCCESS(Status
))
1898 Console
= Buff
->Header
.Console
;
1900 Buff
->DefaultAttrib
= Request
->Data
.SetAttribRequest
.Attrib
;
1901 if (Buff
== Console
->ActiveBuffer
)
1903 if (! ConioUpdateScreenInfo(Console
, Buff
))
1905 ConioUnlockScreenBuffer(Buff
);
1906 return STATUS_UNSUCCESSFUL
;
1910 ConioUnlockScreenBuffer(Buff
);
1912 return STATUS_SUCCESS
;
1915 CSR_API(CsrSetConsoleMode
)
1918 PCSRSS_CONSOLE Console
;
1919 PCSRSS_SCREEN_BUFFER Buff
;
1921 DPRINT("CsrSetConsoleMode\n");
1923 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1924 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1925 Status
= Win32CsrLockObject(ProcessData
,
1926 Request
->Data
.SetConsoleModeRequest
.ConsoleHandle
,
1927 (Object_t
**) &Console
, GENERIC_WRITE
, 0);
1928 if (! NT_SUCCESS(Status
))
1933 Buff
= (PCSRSS_SCREEN_BUFFER
)Console
;
1934 if (CONIO_CONSOLE_MAGIC
== Console
->Header
.Type
)
1936 Console
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_INPUT_MODE_VALID
;
1938 else if (CONIO_SCREEN_BUFFER_MAGIC
== Console
->Header
.Type
)
1940 Buff
->Mode
= Request
->Data
.SetConsoleModeRequest
.Mode
& CONSOLE_OUTPUT_MODE_VALID
;
1944 Status
= STATUS_INVALID_HANDLE
;
1947 Win32CsrUnlockObject((Object_t
*)Console
);
1952 CSR_API(CsrGetConsoleMode
)
1955 PCSRSS_CONSOLE Console
;
1956 PCSRSS_SCREEN_BUFFER Buff
; /* gee, I really wish I could use an anonymous union here */
1958 DPRINT("CsrGetConsoleMode\n");
1960 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
1961 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
1962 Status
= Win32CsrLockObject(ProcessData
, Request
->Data
.GetConsoleModeRequest
.ConsoleHandle
,
1963 (Object_t
**) &Console
, GENERIC_READ
, 0);
1964 if (! NT_SUCCESS(Status
))
1968 Status
= STATUS_SUCCESS
;
1969 Buff
= (PCSRSS_SCREEN_BUFFER
) Console
;
1970 if (CONIO_CONSOLE_MAGIC
== Console
->Header
.Type
)
1972 Request
->Data
.GetConsoleModeRequest
.ConsoleMode
= Console
->Mode
;
1974 else if (CONIO_SCREEN_BUFFER_MAGIC
== Buff
->Header
.Type
)
1976 Request
->Data
.GetConsoleModeRequest
.ConsoleMode
= Buff
->Mode
;
1980 Status
= STATUS_INVALID_HANDLE
;
1983 Win32CsrUnlockObject((Object_t
*)Console
);
1987 CSR_API(CsrCreateScreenBuffer
)
1989 PCSRSS_CONSOLE Console
;
1990 PCSRSS_SCREEN_BUFFER Buff
;
1993 DPRINT("CsrCreateScreenBuffer\n");
1995 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
1996 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
1997 if (! NT_SUCCESS(Status
))
2002 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2003 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2005 Buff
= HeapAlloc(Win32CsrApiHeap
, HEAP_ZERO_MEMORY
, sizeof(CSRSS_SCREEN_BUFFER
));
2009 if (Console
->ActiveBuffer
)
2011 Buff
->MaxX
= Console
->ActiveBuffer
->MaxX
;
2012 Buff
->MaxY
= Console
->ActiveBuffer
->MaxY
;
2013 Buff
->CursorInfo
.bVisible
= Console
->ActiveBuffer
->CursorInfo
.bVisible
;
2014 Buff
->CursorInfo
.dwSize
= Console
->ActiveBuffer
->CursorInfo
.dwSize
;
2018 Buff
->CursorInfo
.bVisible
= TRUE
;
2019 Buff
->CursorInfo
.dwSize
= CSR_DEFAULT_CURSOR_SIZE
;
2022 if (Buff
->MaxX
== 0)
2027 if (Buff
->MaxY
== 0)
2032 Status
= CsrInitConsoleScreenBuffer(Console
, Buff
);
2033 if(NT_SUCCESS(Status
))
2035 Status
= Win32CsrInsertObject(ProcessData
,
2036 &Request
->Data
.CreateScreenBufferRequest
.OutputHandle
,
2038 Request
->Data
.CreateScreenBufferRequest
.Access
,
2039 Request
->Data
.CreateScreenBufferRequest
.Inheritable
,
2040 Request
->Data
.CreateScreenBufferRequest
.ShareMode
);
2045 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2048 ConioUnlockConsole(Console
);
2049 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
2053 CSR_API(CsrSetScreenBuffer
)
2056 PCSRSS_CONSOLE Console
;
2057 PCSRSS_SCREEN_BUFFER Buff
;
2059 DPRINT("CsrSetScreenBuffer\n");
2061 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2062 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2064 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.SetScreenBufferRequest
.OutputHandle
, &Buff
, GENERIC_WRITE
);
2065 if (! NT_SUCCESS(Status
))
2069 Console
= Buff
->Header
.Console
;
2071 if (Buff
== Console
->ActiveBuffer
)
2073 ConioUnlockScreenBuffer(Buff
);
2074 return STATUS_SUCCESS
;
2077 /* If old buffer has no handles, it's now unreferenced */
2078 if (Console
->ActiveBuffer
->Header
.HandleCount
== 0)
2080 ConioDeleteScreenBuffer(Console
->ActiveBuffer
);
2082 /* tie console to new buffer */
2083 Console
->ActiveBuffer
= Buff
;
2084 /* Redraw the console */
2085 ConioDrawConsole(Console
);
2087 ConioUnlockScreenBuffer(Buff
);
2089 return STATUS_SUCCESS
;
2092 CSR_API(CsrSetTitle
)
2095 PCSRSS_CONSOLE Console
;
2098 DPRINT("CsrSetTitle\n");
2100 if (Request
->Header
.u1
.s1
.TotalLength
2101 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_SET_TITLE
)
2102 + Request
->Data
.SetTitleRequest
.Length
)
2104 DPRINT1("Invalid request size\n");
2105 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2106 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2107 return STATUS_INVALID_PARAMETER
;
2110 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
2111 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2112 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2113 if(NT_SUCCESS(Status
))
2115 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Request
->Data
.SetTitleRequest
.Length
);
2118 /* copy title to console */
2119 RtlFreeUnicodeString(&Console
->Title
);
2120 Console
->Title
.Buffer
= Buffer
;
2121 Console
->Title
.Length
= Console
->Title
.MaximumLength
= Request
->Data
.SetTitleRequest
.Length
;
2122 memcpy(Console
->Title
.Buffer
, Request
->Data
.SetTitleRequest
.Title
, Console
->Title
.Length
);
2123 if (! ConioChangeTitle(Console
))
2125 Status
= STATUS_UNSUCCESSFUL
;
2129 Status
= STATUS_SUCCESS
;
2134 Status
= STATUS_NO_MEMORY
;
2136 ConioUnlockConsole(Console
);
2142 CSR_API(CsrGetTitle
)
2145 PCSRSS_CONSOLE Console
;
2148 DPRINT("CsrGetTitle\n");
2150 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2151 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2152 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
2153 if (! NT_SUCCESS(Status
))
2155 DPRINT1("Can't get console\n");
2159 /* Copy title of the console to the user title buffer */
2160 RtlZeroMemory(&Request
->Data
.GetTitleRequest
, sizeof(CSRSS_GET_TITLE
));
2161 Request
->Data
.GetTitleRequest
.Length
= Console
->Title
.Length
;
2162 memcpy (Request
->Data
.GetTitleRequest
.Title
, Console
->Title
.Buffer
,
2163 Console
->Title
.Length
);
2164 Length
= CSR_API_MESSAGE_HEADER_SIZE(CSRSS_SET_TITLE
) + Console
->Title
.Length
;
2166 ConioUnlockConsole(Console
);
2168 if (Length
> sizeof(CSR_API_MESSAGE
))
2170 Request
->Header
.u1
.s1
.TotalLength
= Length
;
2171 Request
->Header
.u1
.s1
.DataLength
= Length
- sizeof(PORT_MESSAGE
);
2173 return STATUS_SUCCESS
;
2176 CSR_API(CsrWriteConsoleOutput
)
2178 SHORT i
, X
, Y
, SizeX
, SizeY
;
2179 PCSRSS_CONSOLE Console
;
2180 PCSRSS_SCREEN_BUFFER Buff
;
2181 SMALL_RECT ScreenBuffer
;
2182 CHAR_INFO
* CurCharInfo
;
2183 SMALL_RECT WriteRegion
;
2184 CHAR_INFO
* CharInfo
;
2191 DPRINT("CsrWriteConsoleOutput\n");
2193 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2194 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2195 Status
= ConioLockScreenBuffer(ProcessData
,
2196 Request
->Data
.WriteConsoleOutputRequest
.ConsoleHandle
,
2199 if (! NT_SUCCESS(Status
))
2203 Console
= Buff
->Header
.Console
;
2205 BufferSize
= Request
->Data
.WriteConsoleOutputRequest
.BufferSize
;
2206 PSize
= BufferSize
.X
* BufferSize
.Y
* sizeof(CHAR_INFO
);
2207 BufferCoord
= Request
->Data
.WriteConsoleOutputRequest
.BufferCoord
;
2208 CharInfo
= Request
->Data
.WriteConsoleOutputRequest
.CharInfo
;
2209 if (((PVOID
)CharInfo
< ProcessData
->CsrSectionViewBase
) ||
2210 (((ULONG_PTR
)CharInfo
+ PSize
) >
2211 ((ULONG_PTR
)ProcessData
->CsrSectionViewBase
+ ProcessData
->CsrSectionViewSize
)))
2213 ConioUnlockScreenBuffer(Buff
);
2214 return STATUS_ACCESS_VIOLATION
;
2216 WriteRegion
= Request
->Data
.WriteConsoleOutputRequest
.WriteRegion
;
2218 SizeY
= min(BufferSize
.Y
- BufferCoord
.Y
, ConioRectHeight(&WriteRegion
));
2219 SizeX
= min(BufferSize
.X
- BufferCoord
.X
, ConioRectWidth(&WriteRegion
));
2220 WriteRegion
.Bottom
= WriteRegion
.Top
+ SizeY
- 1;
2221 WriteRegion
.Right
= WriteRegion
.Left
+ SizeX
- 1;
2223 /* Make sure WriteRegion is inside the screen buffer */
2224 ConioInitRect(&ScreenBuffer
, 0, 0, Buff
->MaxY
- 1, Buff
->MaxX
- 1);
2225 if (! ConioGetIntersection(&WriteRegion
, &ScreenBuffer
, &WriteRegion
))
2227 ConioUnlockScreenBuffer(Buff
);
2229 /* It is okay to have a WriteRegion completely outside the screen buffer.
2230 No data is written then. */
2231 return STATUS_SUCCESS
;
2234 for (i
= 0, Y
= WriteRegion
.Top
; Y
<= WriteRegion
.Bottom
; i
++, Y
++)
2236 CurCharInfo
= CharInfo
+ (i
+ BufferCoord
.Y
) * BufferSize
.X
+ BufferCoord
.X
;
2237 Ptr
= ConioCoordToPointer(Buff
, WriteRegion
.Left
, Y
);
2238 for (X
= WriteRegion
.Left
; X
<= WriteRegion
.Right
; X
++)
2241 if (Request
->Data
.WriteConsoleOutputRequest
.Unicode
)
2243 ConsoleUnicodeCharToAnsiChar(Console
, &AsciiChar
, &CurCharInfo
->Char
.UnicodeChar
);
2247 AsciiChar
= CurCharInfo
->Char
.AsciiChar
;
2250 *Ptr
++ = CurCharInfo
->Attributes
;
2255 ConioDrawRegion(Console
, &WriteRegion
);
2257 ConioUnlockScreenBuffer(Buff
);
2259 Request
->Data
.WriteConsoleOutputRequest
.WriteRegion
.Right
= WriteRegion
.Left
+ SizeX
- 1;
2260 Request
->Data
.WriteConsoleOutputRequest
.WriteRegion
.Bottom
= WriteRegion
.Top
+ SizeY
- 1;
2261 Request
->Data
.WriteConsoleOutputRequest
.WriteRegion
.Left
= WriteRegion
.Left
;
2262 Request
->Data
.WriteConsoleOutputRequest
.WriteRegion
.Top
= WriteRegion
.Top
;
2264 return STATUS_SUCCESS
;
2267 CSR_API(CsrFlushInputBuffer
)
2269 PLIST_ENTRY CurrentEntry
;
2270 PCSRSS_CONSOLE Console
;
2271 ConsoleInput
* Input
;
2274 DPRINT("CsrFlushInputBuffer\n");
2276 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2277 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2278 Status
= ConioLockConsole(ProcessData
,
2279 Request
->Data
.FlushInputBufferRequest
.ConsoleInput
,
2282 if(! NT_SUCCESS(Status
))
2287 /* Discard all entries in the input event queue */
2288 while (!IsListEmpty(&Console
->InputEvents
))
2290 CurrentEntry
= RemoveHeadList(&Console
->InputEvents
);
2291 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
2292 /* Destroy the event */
2293 HeapFree(Win32CsrApiHeap
, 0, Input
);
2295 ResetEvent(Console
->ActiveEvent
);
2296 Console
->WaitingChars
=0;
2298 ConioUnlockConsole(Console
);
2300 return STATUS_SUCCESS
;
2303 CSR_API(CsrScrollConsoleScreenBuffer
)
2305 PCSRSS_CONSOLE Console
;
2306 PCSRSS_SCREEN_BUFFER Buff
;
2307 SMALL_RECT ScreenBuffer
;
2308 SMALL_RECT SrcRegion
;
2309 SMALL_RECT DstRegion
;
2310 SMALL_RECT UpdateRegion
;
2311 SMALL_RECT ScrollRectangle
;
2312 SMALL_RECT ClipRectangle
;
2314 HANDLE ConsoleHandle
;
2315 BOOLEAN UseClipRectangle
;
2316 COORD DestinationOrigin
;
2320 DPRINT("CsrScrollConsoleScreenBuffer\n");
2322 ConsoleHandle
= Request
->Data
.ScrollConsoleScreenBufferRequest
.ConsoleHandle
;
2323 UseClipRectangle
= Request
->Data
.ScrollConsoleScreenBufferRequest
.UseClipRectangle
;
2324 DestinationOrigin
= Request
->Data
.ScrollConsoleScreenBufferRequest
.DestinationOrigin
;
2325 Fill
= Request
->Data
.ScrollConsoleScreenBufferRequest
.Fill
;
2327 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2328 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2329 Status
= ConioLockScreenBuffer(ProcessData
, ConsoleHandle
, &Buff
, GENERIC_WRITE
);
2330 if (! NT_SUCCESS(Status
))
2334 Console
= Buff
->Header
.Console
;
2336 ScrollRectangle
= Request
->Data
.ScrollConsoleScreenBufferRequest
.ScrollRectangle
;
2338 /* Make sure source rectangle is inside the screen buffer */
2339 ConioInitRect(&ScreenBuffer
, 0, 0, Buff
->MaxY
- 1, Buff
->MaxX
- 1);
2340 if (! ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, &ScrollRectangle
))
2342 ConioUnlockScreenBuffer(Buff
);
2343 return STATUS_SUCCESS
;
2346 /* If the source was clipped on the left or top, adjust the destination accordingly */
2347 if (ScrollRectangle
.Left
< 0)
2349 DestinationOrigin
.X
-= ScrollRectangle
.Left
;
2351 if (ScrollRectangle
.Top
< 0)
2353 DestinationOrigin
.Y
-= ScrollRectangle
.Top
;
2356 if (UseClipRectangle
)
2358 ClipRectangle
= Request
->Data
.ScrollConsoleScreenBufferRequest
.ClipRectangle
;
2359 if (!ConioGetIntersection(&ClipRectangle
, &ClipRectangle
, &ScreenBuffer
))
2361 ConioUnlockScreenBuffer(Buff
);
2362 return STATUS_SUCCESS
;
2367 ClipRectangle
= ScreenBuffer
;
2370 ConioInitRect(&DstRegion
,
2371 DestinationOrigin
.Y
,
2372 DestinationOrigin
.X
,
2373 DestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
2374 DestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
2376 if (Request
->Data
.ScrollConsoleScreenBufferRequest
.Unicode
)
2377 ConsoleUnicodeCharToAnsiChar(Console
, &FillChar
, &Fill
.Char
.UnicodeChar
);
2379 FillChar
= Fill
.Char
.AsciiChar
;
2381 ConioMoveRegion(Buff
, &SrcRegion
, &DstRegion
, &ClipRectangle
, Fill
.Attributes
<< 8 | (BYTE
)FillChar
);
2383 if (Buff
== Console
->ActiveBuffer
)
2385 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
2386 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &ClipRectangle
))
2388 /* Draw update region */
2389 ConioDrawRegion(Console
, &UpdateRegion
);
2393 ConioUnlockScreenBuffer(Buff
);
2395 return STATUS_SUCCESS
;
2398 CSR_API(CsrReadConsoleOutputChar
)
2401 PCSRSS_CONSOLE Console
;
2402 PCSRSS_SCREEN_BUFFER Buff
;
2409 DPRINT("CsrReadConsoleOutputChar\n");
2411 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2412 Request
->Header
.u1
.s1
.DataLength
= Request
->Header
.u1
.s1
.TotalLength
- sizeof(PORT_MESSAGE
);
2413 ReadBuffer
= Request
->Data
.ReadConsoleOutputCharRequest
.String
;
2415 CharSize
= (Request
->Data
.ReadConsoleOutputCharRequest
.Unicode
? sizeof(WCHAR
) : sizeof(CHAR
));
2417 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.ReadConsoleOutputCharRequest
.ConsoleHandle
, &Buff
, GENERIC_READ
);
2418 if (! NT_SUCCESS(Status
))
2422 Console
= Buff
->Header
.Console
;
2424 Xpos
= Request
->Data
.ReadConsoleOutputCharRequest
.ReadCoord
.X
;
2425 Ypos
= (Request
->Data
.ReadConsoleOutputCharRequest
.ReadCoord
.Y
+ Buff
->VirtualY
) % Buff
->MaxY
;
2427 for (i
= 0; i
< Request
->Data
.ReadConsoleOutputCharRequest
.NumCharsToRead
; ++i
)
2429 Char
= Buff
->Buffer
[(Xpos
* 2) + (Ypos
* 2 * Buff
->MaxX
)];
2431 if(Request
->Data
.ReadConsoleOutputCharRequest
.Unicode
)
2433 ConsoleAnsiCharToUnicodeChar(Console
, (WCHAR
*)ReadBuffer
, &Char
);
2434 ReadBuffer
+= sizeof(WCHAR
);
2437 *(ReadBuffer
++) = Char
;
2441 if (Xpos
== Buff
->MaxX
)
2446 if (Ypos
== Buff
->MaxY
)
2454 Request
->Data
.ReadConsoleOutputCharRequest
.EndCoord
.X
= Xpos
;
2455 Request
->Data
.ReadConsoleOutputCharRequest
.EndCoord
.Y
= (Ypos
- Buff
->VirtualY
+ Buff
->MaxY
) % Buff
->MaxY
;
2457 ConioUnlockScreenBuffer(Buff
);
2459 Request
->Data
.ReadConsoleOutputCharRequest
.CharsRead
= (DWORD
)((ULONG_PTR
)ReadBuffer
- (ULONG_PTR
)Request
->Data
.ReadConsoleOutputCharRequest
.String
) / CharSize
;
2460 if (Request
->Data
.ReadConsoleOutputCharRequest
.CharsRead
* CharSize
+ CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR
) > sizeof(CSR_API_MESSAGE
))
2462 Request
->Header
.u1
.s1
.TotalLength
= Request
->Data
.ReadConsoleOutputCharRequest
.CharsRead
* CharSize
+ CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR
);
2463 Request
->Header
.u1
.s1
.DataLength
= Request
->Header
.u1
.s1
.TotalLength
- sizeof(PORT_MESSAGE
);
2466 return STATUS_SUCCESS
;
2470 CSR_API(CsrReadConsoleOutputAttrib
)
2473 PCSRSS_SCREEN_BUFFER Buff
;
2477 DWORD CurrentLength
;
2479 DPRINT("CsrReadConsoleOutputAttrib\n");
2481 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2482 Request
->Header
.u1
.s1
.DataLength
= Request
->Header
.u1
.s1
.TotalLength
- sizeof(PORT_MESSAGE
);
2483 ReadBuffer
= Request
->Data
.ReadConsoleOutputAttribRequest
.Attribute
;
2485 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.ReadConsoleOutputAttribRequest
.ConsoleHandle
, &Buff
, GENERIC_READ
);
2486 if (! NT_SUCCESS(Status
))
2491 Xpos
= Request
->Data
.ReadConsoleOutputAttribRequest
.ReadCoord
.X
;
2492 Ypos
= (Request
->Data
.ReadConsoleOutputAttribRequest
.ReadCoord
.Y
+ Buff
->VirtualY
) % Buff
->MaxY
;
2494 for (i
= 0; i
< Request
->Data
.ReadConsoleOutputAttribRequest
.NumAttrsToRead
; ++i
)
2496 *ReadBuffer
= Buff
->Buffer
[(Xpos
* 2) + (Ypos
* 2 * Buff
->MaxX
) + 1];
2501 if (Xpos
== Buff
->MaxX
)
2506 if (Ypos
== Buff
->MaxY
)
2515 Request
->Data
.ReadConsoleOutputAttribRequest
.EndCoord
.X
= Xpos
;
2516 Request
->Data
.ReadConsoleOutputAttribRequest
.EndCoord
.Y
= (Ypos
- Buff
->VirtualY
+ Buff
->MaxY
) % Buff
->MaxY
;
2518 ConioUnlockScreenBuffer(Buff
);
2520 CurrentLength
= CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_ATTRIB
)
2521 + Request
->Data
.ReadConsoleOutputAttribRequest
.NumAttrsToRead
* sizeof(WORD
);
2522 if (CurrentLength
> sizeof(CSR_API_MESSAGE
))
2524 Request
->Header
.u1
.s1
.TotalLength
= CurrentLength
;
2525 Request
->Header
.u1
.s1
.DataLength
= CurrentLength
- sizeof(PORT_MESSAGE
);
2528 return STATUS_SUCCESS
;
2532 CSR_API(CsrGetNumberOfConsoleInputEvents
)
2535 PCSRSS_CONSOLE Console
;
2536 PLIST_ENTRY CurrentItem
;
2538 ConsoleInput
*Input
;
2540 DPRINT("CsrGetNumberOfConsoleInputEvents\n");
2542 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2543 Request
->Header
.u1
.s1
.DataLength
= Request
->Header
.u1
.s1
.TotalLength
- sizeof(PORT_MESSAGE
);
2545 Status
= ConioLockConsole(ProcessData
, Request
->Data
.GetNumInputEventsRequest
.ConsoleHandle
, &Console
, GENERIC_READ
);
2546 if (! NT_SUCCESS(Status
))
2551 CurrentItem
= Console
->InputEvents
.Flink
;
2554 /* If there are any events ... */
2555 while (CurrentItem
!= &Console
->InputEvents
)
2557 Input
= CONTAINING_RECORD(CurrentItem
, ConsoleInput
, ListEntry
);
2558 CurrentItem
= CurrentItem
->Flink
;
2565 ConioUnlockConsole(Console
);
2567 Request
->Data
.GetNumInputEventsRequest
.NumInputEvents
= NumEvents
;
2569 return STATUS_SUCCESS
;
2573 CSR_API(CsrPeekConsoleInput
)
2576 PCSRSS_CONSOLE Console
;
2579 PLIST_ENTRY CurrentItem
;
2580 PINPUT_RECORD InputRecord
;
2584 DPRINT("CsrPeekConsoleInput\n");
2586 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2587 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2589 Status
= ConioLockConsole(ProcessData
, Request
->Data
.GetNumInputEventsRequest
.ConsoleHandle
, &Console
, GENERIC_READ
);
2590 if(! NT_SUCCESS(Status
))
2595 InputRecord
= Request
->Data
.PeekConsoleInputRequest
.InputRecord
;
2596 Length
= Request
->Data
.PeekConsoleInputRequest
.Length
;
2597 Size
= Length
* sizeof(INPUT_RECORD
);
2599 if (((PVOID
)InputRecord
< ProcessData
->CsrSectionViewBase
)
2600 || (((ULONG_PTR
)InputRecord
+ Size
) > ((ULONG_PTR
)ProcessData
->CsrSectionViewBase
+ ProcessData
->CsrSectionViewSize
)))
2602 ConioUnlockConsole(Console
);
2603 return STATUS_ACCESS_VIOLATION
;
2608 if (! IsListEmpty(&Console
->InputEvents
))
2610 CurrentItem
= Console
->InputEvents
.Flink
;
2612 while (CurrentItem
!= &Console
->InputEvents
&& NumItems
< Length
)
2614 Item
= CONTAINING_RECORD(CurrentItem
, ConsoleInput
, ListEntry
);
2618 CurrentItem
= CurrentItem
->Flink
;
2623 *InputRecord
= Item
->InputEvent
;
2625 if (Request
->Data
.ReadInputRequest
.Unicode
== FALSE
)
2627 ConioInputEventToAnsi(Console
, InputRecord
);
2631 CurrentItem
= CurrentItem
->Flink
;
2635 ConioUnlockConsole(Console
);
2637 Request
->Data
.PeekConsoleInputRequest
.Length
= NumItems
;
2639 return STATUS_SUCCESS
;
2643 CSR_API(CsrReadConsoleOutput
)
2645 PCHAR_INFO CharInfo
;
2646 PCHAR_INFO CurCharInfo
;
2647 PCSRSS_SCREEN_BUFFER Buff
;
2654 SMALL_RECT ReadRegion
;
2655 SMALL_RECT ScreenRect
;
2661 DPRINT("CsrReadConsoleOutput\n");
2663 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2664 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2666 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.ReadConsoleOutputRequest
.ConsoleHandle
, &Buff
, GENERIC_READ
);
2667 if (! NT_SUCCESS(Status
))
2672 CharInfo
= Request
->Data
.ReadConsoleOutputRequest
.CharInfo
;
2673 ReadRegion
= Request
->Data
.ReadConsoleOutputRequest
.ReadRegion
;
2674 BufferSize
= Request
->Data
.ReadConsoleOutputRequest
.BufferSize
;
2675 BufferCoord
= Request
->Data
.ReadConsoleOutputRequest
.BufferCoord
;
2676 Length
= BufferSize
.X
* BufferSize
.Y
;
2677 Size
= Length
* sizeof(CHAR_INFO
);
2679 /* FIXME: Is this correct? */
2680 CodePage
= ProcessData
->Console
->OutputCodePage
;
2682 if (((PVOID
)CharInfo
< ProcessData
->CsrSectionViewBase
)
2683 || (((ULONG_PTR
)CharInfo
+ Size
) > ((ULONG_PTR
)ProcessData
->CsrSectionViewBase
+ ProcessData
->CsrSectionViewSize
)))
2685 ConioUnlockScreenBuffer(Buff
);
2686 return STATUS_ACCESS_VIOLATION
;
2689 SizeY
= min(BufferSize
.Y
- BufferCoord
.Y
, ConioRectHeight(&ReadRegion
));
2690 SizeX
= min(BufferSize
.X
- BufferCoord
.X
, ConioRectWidth(&ReadRegion
));
2691 ReadRegion
.Bottom
= ReadRegion
.Top
+ SizeY
;
2692 ReadRegion
.Right
= ReadRegion
.Left
+ SizeX
;
2694 ConioInitRect(&ScreenRect
, 0, 0, Buff
->MaxY
, Buff
->MaxX
);
2695 if (! ConioGetIntersection(&ReadRegion
, &ScreenRect
, &ReadRegion
))
2697 ConioUnlockScreenBuffer(Buff
);
2698 return STATUS_SUCCESS
;
2701 for (i
= 0, Y
= ReadRegion
.Top
; Y
< ReadRegion
.Bottom
; ++i
, ++Y
)
2703 CurCharInfo
= CharInfo
+ (i
* BufferSize
.X
);
2705 Ptr
= ConioCoordToPointer(Buff
, ReadRegion
.Left
, Y
);
2706 for (X
= ReadRegion
.Left
; X
< ReadRegion
.Right
; ++X
)
2708 if (Request
->Data
.ReadConsoleOutputRequest
.Unicode
)
2710 MultiByteToWideChar(CodePage
, 0,
2712 &CurCharInfo
->Char
.UnicodeChar
, 1);
2716 CurCharInfo
->Char
.AsciiChar
= *Ptr
++;
2718 CurCharInfo
->Attributes
= *Ptr
++;
2723 ConioUnlockScreenBuffer(Buff
);
2725 Request
->Data
.ReadConsoleOutputRequest
.ReadRegion
.Right
= ReadRegion
.Left
+ SizeX
- 1;
2726 Request
->Data
.ReadConsoleOutputRequest
.ReadRegion
.Bottom
= ReadRegion
.Top
+ SizeY
- 1;
2727 Request
->Data
.ReadConsoleOutputRequest
.ReadRegion
.Left
= ReadRegion
.Left
;
2728 Request
->Data
.ReadConsoleOutputRequest
.ReadRegion
.Top
= ReadRegion
.Top
;
2730 return STATUS_SUCCESS
;
2734 CSR_API(CsrWriteConsoleInput
)
2736 PINPUT_RECORD InputRecord
;
2737 PCSRSS_CONSOLE Console
;
2742 ConsoleInput
* Record
;
2744 DPRINT("CsrWriteConsoleInput\n");
2746 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2747 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2749 Status
= ConioLockConsole(ProcessData
, Request
->Data
.WriteConsoleInputRequest
.ConsoleHandle
, &Console
, GENERIC_WRITE
);
2750 if (! NT_SUCCESS(Status
))
2755 InputRecord
= Request
->Data
.WriteConsoleInputRequest
.InputRecord
;
2756 Length
= Request
->Data
.WriteConsoleInputRequest
.Length
;
2757 Size
= Length
* sizeof(INPUT_RECORD
);
2759 if (((PVOID
)InputRecord
< ProcessData
->CsrSectionViewBase
)
2760 || (((ULONG_PTR
)InputRecord
+ Size
) > ((ULONG_PTR
)ProcessData
->CsrSectionViewBase
+ ProcessData
->CsrSectionViewSize
)))
2762 ConioUnlockConsole(Console
);
2763 return STATUS_ACCESS_VIOLATION
;
2766 for (i
= 0; i
< Length
; i
++)
2768 Record
= HeapAlloc(Win32CsrApiHeap
, 0, sizeof(ConsoleInput
));
2771 ConioUnlockConsole(Console
);
2772 return STATUS_INSUFFICIENT_RESOURCES
;
2775 Record
->Echoed
= FALSE
;
2776 Record
->Fake
= FALSE
;
2777 //Record->InputEvent = *InputRecord++;
2778 memcpy(&Record
->InputEvent
, &InputRecord
[i
], sizeof(INPUT_RECORD
));
2779 if (KEY_EVENT
== Record
->InputEvent
.EventType
)
2781 /* FIXME - convert from unicode to ascii!! */
2782 ConioProcessChar(Console
, Record
);
2786 ConioUnlockConsole(Console
);
2788 Request
->Data
.WriteConsoleInputRequest
.Length
= i
;
2790 return STATUS_SUCCESS
;
2793 /**********************************************************************
2794 * HardwareStateProperty
2797 * Set/Get the value of the HardwareState and switch
2798 * between direct video buffer ouput and GDI windowed
2801 * Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
2802 * object. We use the same object to Request.
2804 * ConsoleHwState has the correct size to be compatible
2805 * with NT's, but values are not.
2807 static NTSTATUS FASTCALL
2808 SetConsoleHardwareState (PCSRSS_CONSOLE Console
, DWORD ConsoleHwState
)
2810 DPRINT1("Console Hardware State: %d\n", ConsoleHwState
);
2812 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED
== ConsoleHwState
)
2813 ||(CONSOLE_HARDWARE_STATE_DIRECT
== ConsoleHwState
))
2815 if (Console
->HardwareState
!= ConsoleHwState
)
2817 /* TODO: implement switching from full screen to windowed mode */
2818 /* TODO: or back; now simply store the hardware state */
2819 Console
->HardwareState
= ConsoleHwState
;
2822 return STATUS_SUCCESS
;
2825 return STATUS_INVALID_PARAMETER_3
; /* Client: (handle, set_get, [mode]) */
2828 CSR_API(CsrHardwareStateProperty
)
2830 PCSRSS_CONSOLE Console
;
2833 DPRINT("CsrHardwareStateProperty\n");
2835 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2836 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2838 Status
= ConioLockConsole(ProcessData
,
2839 Request
->Data
.ConsoleHardwareStateRequest
.ConsoleHandle
,
2842 if (! NT_SUCCESS(Status
))
2844 DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
2848 switch (Request
->Data
.ConsoleHardwareStateRequest
.SetGet
)
2850 case CONSOLE_HARDWARE_STATE_GET
:
2851 Request
->Data
.ConsoleHardwareStateRequest
.State
= Console
->HardwareState
;
2854 case CONSOLE_HARDWARE_STATE_SET
:
2855 DPRINT("Setting console hardware state.\n");
2856 Status
= SetConsoleHardwareState(Console
, Request
->Data
.ConsoleHardwareStateRequest
.State
);
2860 Status
= STATUS_INVALID_PARAMETER_2
; /* Client: (handle, [set_get], mode) */
2864 ConioUnlockConsole(Console
);
2869 CSR_API(CsrGetConsoleWindow
)
2871 PCSRSS_CONSOLE Console
;
2874 DPRINT("CsrGetConsoleWindow\n");
2876 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2877 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2879 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
2880 if (! NT_SUCCESS(Status
))
2885 Request
->Data
.GetConsoleWindowRequest
.WindowHandle
= Console
->hWindow
;
2886 ConioUnlockConsole(Console
);
2888 return STATUS_SUCCESS
;
2891 CSR_API(CsrSetConsoleIcon
)
2893 PCSRSS_CONSOLE Console
;
2896 DPRINT("CsrSetConsoleIcon\n");
2898 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2899 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2901 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
2902 if (! NT_SUCCESS(Status
))
2907 Status
= (ConioChangeIcon(Console
, Request
->Data
.SetConsoleIconRequest
.WindowIcon
)
2908 ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
2909 ConioUnlockConsole(Console
);
2914 CSR_API(CsrGetConsoleCodePage
)
2916 PCSRSS_CONSOLE Console
;
2919 DPRINT("CsrGetConsoleCodePage\n");
2921 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
2922 if (! NT_SUCCESS(Status
))
2927 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2928 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2929 Request
->Data
.GetConsoleCodePage
.CodePage
= Console
->CodePage
;
2930 ConioUnlockConsole(Console
);
2931 return STATUS_SUCCESS
;
2934 CSR_API(CsrSetConsoleCodePage
)
2936 PCSRSS_CONSOLE Console
;
2939 DPRINT("CsrSetConsoleCodePage\n");
2941 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
2942 if (! NT_SUCCESS(Status
))
2947 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2948 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2950 if (IsValidCodePage(Request
->Data
.SetConsoleCodePage
.CodePage
))
2952 Console
->CodePage
= Request
->Data
.SetConsoleCodePage
.CodePage
;
2953 ConioUnlockConsole(Console
);
2954 return STATUS_SUCCESS
;
2957 ConioUnlockConsole(Console
);
2958 return STATUS_INVALID_PARAMETER
;
2961 CSR_API(CsrGetConsoleOutputCodePage
)
2963 PCSRSS_CONSOLE Console
;
2966 DPRINT("CsrGetConsoleOutputCodePage\n");
2968 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
2969 if (! NT_SUCCESS(Status
))
2974 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2975 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2976 Request
->Data
.GetConsoleOutputCodePage
.CodePage
= Console
->OutputCodePage
;
2977 ConioUnlockConsole(Console
);
2978 return STATUS_SUCCESS
;
2981 CSR_API(CsrSetConsoleOutputCodePage
)
2983 PCSRSS_CONSOLE Console
;
2986 DPRINT("CsrSetConsoleOutputCodePage\n");
2988 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
2989 if (! NT_SUCCESS(Status
))
2994 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
2995 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
2997 if (IsValidCodePage(Request
->Data
.SetConsoleOutputCodePage
.CodePage
))
2999 Console
->OutputCodePage
= Request
->Data
.SetConsoleOutputCodePage
.CodePage
;
3000 ConioUnlockConsole(Console
);
3001 return STATUS_SUCCESS
;
3004 ConioUnlockConsole(Console
);
3005 return STATUS_INVALID_PARAMETER
;
3008 CSR_API(CsrGetProcessList
)
3011 PCSRSS_CONSOLE Console
;
3012 PCSRSS_PROCESS_DATA current
;
3013 PLIST_ENTRY current_entry
;
3018 DPRINT("CsrGetProcessList\n");
3020 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
3021 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
3023 Buffer
= Request
->Data
.GetProcessListRequest
.ProcessId
;
3024 Offset
= (PBYTE
)Buffer
- (PBYTE
)ProcessData
->CsrSectionViewBase
;
3025 if (Offset
>= ProcessData
->CsrSectionViewSize
3026 || (Request
->Data
.GetProcessListRequest
.nMaxIds
* sizeof(DWORD
)) > (ProcessData
->CsrSectionViewSize
- Offset
)
3027 || Offset
& (sizeof(DWORD
) - 1))
3029 return STATUS_ACCESS_VIOLATION
;
3032 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
3033 if (! NT_SUCCESS(Status
))
3038 for(current_entry
= Console
->ProcessList
.Flink
;
3039 current_entry
!= &Console
->ProcessList
;
3040 current_entry
= current_entry
->Flink
)
3042 current
= CONTAINING_RECORD(current_entry
, CSRSS_PROCESS_DATA
, ProcessEntry
);
3043 if(++nItems
<= Request
->Data
.GetProcessListRequest
.nMaxIds
)
3045 *Buffer
++ = (DWORD
)current
->ProcessId
;
3049 ConioUnlockConsole(Console
);
3051 Request
->Data
.GetProcessListRequest
.nProcessIdsTotal
= nItems
;
3052 return STATUS_SUCCESS
;
3055 CSR_API(CsrGenerateCtrlEvent
)
3057 PCSRSS_CONSOLE Console
;
3058 PCSRSS_PROCESS_DATA current
;
3059 PLIST_ENTRY current_entry
;
3063 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
3064 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
3066 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
3067 if (! NT_SUCCESS(Status
))
3072 Group
= Request
->Data
.GenerateCtrlEvent
.ProcessGroup
;
3073 Status
= STATUS_INVALID_PARAMETER
;
3074 for (current_entry
= Console
->ProcessList
.Flink
;
3075 current_entry
!= &Console
->ProcessList
;
3076 current_entry
= current_entry
->Flink
)
3078 current
= CONTAINING_RECORD(current_entry
, CSRSS_PROCESS_DATA
, ProcessEntry
);
3079 if (Group
== 0 || current
->ProcessGroup
== Group
)
3081 ConioConsoleCtrlEvent(Request
->Data
.GenerateCtrlEvent
.Event
, current
);
3082 Status
= STATUS_SUCCESS
;
3086 ConioUnlockConsole(Console
);
3091 CSR_API(CsrSetScreenBufferSize
)
3094 PCSRSS_CONSOLE Console
;
3095 PCSRSS_SCREEN_BUFFER Buff
;
3097 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
3098 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
3100 Status
= ConioLockScreenBuffer(ProcessData
, Request
->Data
.SetScreenBufferSize
.OutputHandle
, &Buff
, GENERIC_WRITE
);
3101 if (!NT_SUCCESS(Status
))
3105 Console
= Buff
->Header
.Console
;
3107 Status
= ConioResizeBuffer(Console
, Buff
, Request
->Data
.SetScreenBufferSize
.Size
);
3108 ConioUnlockScreenBuffer(Buff
);
3113 CSR_API(CsrGetConsoleSelectionInfo
)
3116 PCSRSS_CONSOLE Console
;
3118 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
3119 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
3121 Status
= ConioConsoleFromProcessData(ProcessData
, &Console
);
3122 if (NT_SUCCESS(Status
))
3124 memset(&Request
->Data
.GetConsoleSelectionInfo
.Info
, 0, sizeof(CONSOLE_SELECTION_INFO
));
3125 if (Console
->Selection
.dwFlags
!= 0)
3126 Request
->Data
.GetConsoleSelectionInfo
.Info
= Console
->Selection
;
3127 ConioUnlockConsole(Console
);