2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: win32ss/user/winsrv/consrv/condrv/text.c
5 * PURPOSE: Console Output Functions for text-mode screen-buffers
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
21 /* PRIVATE FUNCTIONS **********************************************************/
23 CONSOLE_IO_OBJECT_TYPE
24 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This
)
26 // return This->Header.Type;
27 return TEXTMODE_BUFFER
;
30 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl
=
32 TEXTMODE_BUFFER_GetType
,
37 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
);
41 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
42 IN OUT PCONSOLE Console
,
45 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
);
49 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
50 IN OUT PCONSOLE Console
,
51 IN PTEXTMODE_BUFFER_INFO TextModeInfo
)
53 NTSTATUS Status
= STATUS_SUCCESS
;
54 PTEXTMODE_SCREEN_BUFFER NewBuffer
= NULL
;
56 if (Console
== NULL
|| Buffer
== NULL
|| TextModeInfo
== NULL
)
57 return STATUS_INVALID_PARAMETER
;
61 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
63 sizeof(TEXTMODE_SCREEN_BUFFER
));
64 if (!NT_SUCCESS(Status
)) return Status
;
65 NewBuffer
->Header
.Type
= TEXTMODE_BUFFER
;
66 NewBuffer
->Vtbl
= &TextVtbl
;
68 NewBuffer
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
69 TextModeInfo
->ScreenBufferSize
.X
*
70 TextModeInfo
->ScreenBufferSize
.Y
*
72 if (NewBuffer
->Buffer
== NULL
)
74 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
75 return STATUS_INSUFFICIENT_RESOURCES
;
78 NewBuffer
->ScreenBufferSize
= NewBuffer
->OldScreenBufferSize
79 = TextModeInfo
->ScreenBufferSize
;
80 NewBuffer
->ViewSize
= NewBuffer
->OldViewSize
81 = Console
->ConsoleSize
;
83 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
84 NewBuffer
->VirtualY
= 0;
86 NewBuffer
->CursorBlinkOn
= NewBuffer
->ForceCursorOff
= FALSE
;
87 NewBuffer
->CursorInfo
.bVisible
= (TextModeInfo
->IsCursorVisible
&& (TextModeInfo
->CursorSize
!= 0));
88 NewBuffer
->CursorInfo
.dwSize
= min(max(TextModeInfo
->CursorSize
, 0), 100);
90 NewBuffer
->ScreenDefaultAttrib
= TextModeInfo
->ScreenAttrib
;
91 NewBuffer
->PopupDefaultAttrib
= TextModeInfo
->PopupAttrib
;
93 /* Initialize buffer to be empty with default attributes */
94 for (NewBuffer
->CursorPosition
.Y
= 0 ; NewBuffer
->CursorPosition
.Y
< NewBuffer
->ScreenBufferSize
.Y
; NewBuffer
->CursorPosition
.Y
++)
96 ClearLineBuffer(NewBuffer
);
98 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
100 NewBuffer
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
102 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
103 return STATUS_SUCCESS
;
107 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
109 PTEXTMODE_SCREEN_BUFFER Buff
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
112 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
113 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
115 Buffer
->Header
.Type
= SCREEN_BUFFER
;
117 ConsoleFreeHeap(Buff
->Buffer
);
119 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);
124 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
126 return &Buff
->Buffer
[((Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
) * Buff
->ScreenBufferSize
.X
+ X
];
130 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
)
132 PCHAR_INFO Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CursorPosition
.Y
);
135 for (Pos
= 0; Pos
< Buff
->ScreenBufferSize
.X
; Pos
++, Ptr
++)
138 Ptr
->Char
.UnicodeChar
= L
' ';
139 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
143 static __inline BOOLEAN
144 ConioGetIntersection(OUT PSMALL_RECT Intersection
,
145 IN PSMALL_RECT Rect1
,
146 IN PSMALL_RECT Rect2
)
148 if ( ConioIsRectEmpty(Rect1
) ||
149 ConioIsRectEmpty(Rect2
) ||
150 (Rect1
->Top
> Rect2
->Bottom
) ||
151 (Rect1
->Left
> Rect2
->Right
) ||
152 (Rect1
->Bottom
< Rect2
->Top
) ||
153 (Rect1
->Right
< Rect2
->Left
) )
155 /* The rectangles do not intersect */
156 ConioInitRect(Intersection
, 0, -1, 0, -1);
160 ConioInitRect(Intersection
,
161 max(Rect1
->Top
, Rect2
->Top
),
162 max(Rect1
->Left
, Rect2
->Left
),
163 min(Rect1
->Bottom
, Rect2
->Bottom
),
164 min(Rect1
->Right
, Rect2
->Right
));
169 static __inline BOOLEAN
170 ConioGetUnion(OUT PSMALL_RECT Union
,
171 IN PSMALL_RECT Rect1
,
172 IN PSMALL_RECT Rect2
)
174 if (ConioIsRectEmpty(Rect1
))
176 if (ConioIsRectEmpty(Rect2
))
178 ConioInitRect(Union
, 0, -1, 0, -1);
186 else if (ConioIsRectEmpty(Rect2
))
193 min(Rect1
->Top
, Rect2
->Top
),
194 min(Rect1
->Left
, Rect2
->Left
),
195 max(Rect1
->Bottom
, Rect2
->Bottom
),
196 max(Rect1
->Right
, Rect2
->Right
));
203 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff
,
204 IN OUT PSMALL_RECT UpdateRect
,
208 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
210 UpdateRect
->Left
= 0;
214 UpdateRect
->Left
= Start
->X
;
216 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
218 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
222 UpdateRect
->Right
= Start
->X
+ Length
- 1;
224 UpdateRect
->Top
= Start
->Y
;
225 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->ScreenBufferSize
.X
;
226 if (Buff
->ScreenBufferSize
.Y
<= UpdateRect
->Bottom
)
228 UpdateRect
->Bottom
= Buff
->ScreenBufferSize
.Y
- 1;
233 * Move from one rectangle to another. We must be careful about the order that
234 * this is done, to avoid overwriting parts of the source before they are moved.
237 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
238 PSMALL_RECT SrcRegion
,
239 PSMALL_RECT DstRegion
,
240 PSMALL_RECT ClipRegion
,
243 int Width
= ConioRectWidth(SrcRegion
);
244 int Height
= ConioRectHeight(SrcRegion
);
255 /* Moving down: work from bottom up */
256 SY
= SrcRegion
->Bottom
;
257 DY
= DstRegion
->Bottom
;
260 for (i
= 0; i
< Height
; i
++)
262 PCHAR_INFO SRow
= ConioCoordToPointer(ScreenBuffer
, 0, SY
);
263 PCHAR_INFO DRow
= ConioCoordToPointer(ScreenBuffer
, 0, DY
);
265 SX
= SrcRegion
->Left
;
266 DX
= DstRegion
->Left
;
270 /* Moving right: work from right to left */
271 SX
= SrcRegion
->Right
;
272 DX
= DstRegion
->Right
;
275 for (j
= 0; j
< Width
; j
++)
277 CHAR_INFO Cell
= SRow
[SX
];
278 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
&&
279 SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
283 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
&&
284 DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
297 ConioEffectiveCursorSize(PCONSOLE Console
, DWORD Scale
)
299 DWORD Size
= (Console
->ActiveBuffer
->CursorInfo
.dwSize
* Scale
+ 99) / 100;
300 /* If line input in progress, perhaps adjust for insert toggle */
301 if (Console
->LineBuffer
&& !Console
->LineComplete
&& Console
->LineInsertToggle
)
302 return (Size
* 2 <= Scale
) ? (Size
* 2) : (Size
/ 2);
307 ConioResizeBuffer(PCONSOLE Console
,
308 PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
314 WORD CurrentAttribute
;
316 PCHAR_INFO OldBuffer
;
320 /* Buffer size is not allowed to be smaller than the view size */
321 if (Size
.X
< ScreenBuffer
->ViewSize
.X
|| Size
.Y
< ScreenBuffer
->ViewSize
.Y
)
322 return STATUS_INVALID_PARAMETER
;
324 if (Size
.X
== ScreenBuffer
->ScreenBufferSize
.X
&& Size
.Y
== ScreenBuffer
->ScreenBufferSize
.Y
)
326 // FIXME: Trigger a buffer resize event ??
327 return STATUS_SUCCESS
;
330 if (Console
->FixedSize
)
333 * The console is in fixed-size mode, so we cannot resize anything
334 * at the moment. However, keep those settings somewhere so that
335 * we can try to set them up when we will be allowed to do so.
337 ScreenBuffer
->OldScreenBufferSize
= Size
;
338 return STATUS_NOT_SUPPORTED
; // STATUS_SUCCESS
341 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
.X
* Size
.Y
* sizeof(CHAR_INFO
));
342 if (!Buffer
) return STATUS_NO_MEMORY
;
344 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer
->ScreenBufferSize
.X
, ScreenBuffer
->ScreenBufferSize
.Y
, Size
.X
, Size
.Y
);
345 OldBuffer
= ScreenBuffer
->Buffer
;
347 for (CurrentY
= 0; CurrentY
< ScreenBuffer
->ScreenBufferSize
.Y
&& CurrentY
< Size
.Y
; CurrentY
++)
349 ptr
= ConioCoordToPointer(ScreenBuffer
, 0, CurrentY
);
350 if (Size
.X
<= ScreenBuffer
->ScreenBufferSize
.X
)
353 RtlCopyMemory(Buffer
+ Offset
, ptr
, Size
.X
* sizeof(CHAR_INFO
));
359 RtlCopyMemory(Buffer
+ Offset
, ptr
, ScreenBuffer
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
));
360 Offset
+= ScreenBuffer
->ScreenBufferSize
.X
;
362 /* The attribute to be used is the one of the last cell of the current line */
363 CurrentAttribute
= ConioCoordToPointer(ScreenBuffer
,
364 ScreenBuffer
->ScreenBufferSize
.X
- 1,
365 CurrentY
)->Attributes
;
367 diff
= Size
.X
- ScreenBuffer
->ScreenBufferSize
.X
;
369 /* Zero-out the new part of the buffer */
370 for (i
= 0; i
< diff
; i
++)
372 ptr
= Buffer
+ Offset
;
373 ptr
->Char
.UnicodeChar
= L
' ';
374 ptr
->Attributes
= CurrentAttribute
;
380 if (Size
.Y
> ScreenBuffer
->ScreenBufferSize
.Y
)
382 diff
= Size
.X
* (Size
.Y
- ScreenBuffer
->ScreenBufferSize
.Y
);
384 /* Zero-out the new part of the buffer */
385 for (i
= 0; i
< diff
; i
++)
387 ptr
= Buffer
+ Offset
;
388 ptr
->Char
.UnicodeChar
= L
' ';
389 ptr
->Attributes
= ScreenBuffer
->ScreenDefaultAttrib
;
394 (void)InterlockedExchangePointer((PVOID
volatile*)&ScreenBuffer
->Buffer
, Buffer
);
395 ConsoleFreeHeap(OldBuffer
);
396 ScreenBuffer
->ScreenBufferSize
= ScreenBuffer
->OldScreenBufferSize
= Size
;
397 ScreenBuffer
->VirtualY
= 0;
399 /* Ensure cursor and window are within buffer */
400 if (ScreenBuffer
->CursorPosition
.X
>= Size
.X
)
401 ScreenBuffer
->CursorPosition
.X
= Size
.X
- 1;
402 if (ScreenBuffer
->CursorPosition
.Y
>= Size
.Y
)
403 ScreenBuffer
->CursorPosition
.Y
= Size
.Y
- 1;
404 if (ScreenBuffer
->ViewOrigin
.X
> Size
.X
- ScreenBuffer
->ViewSize
.X
)
405 ScreenBuffer
->ViewOrigin
.X
= Size
.X
- ScreenBuffer
->ViewSize
.X
;
406 if (ScreenBuffer
->ViewOrigin
.Y
> Size
.Y
- ScreenBuffer
->ViewSize
.Y
)
407 ScreenBuffer
->ViewOrigin
.Y
= Size
.Y
- ScreenBuffer
->ViewSize
.Y
;
410 * Trigger a buffer resize event
412 if (Console
->InputBuffer
.Mode
& ENABLE_WINDOW_INPUT
)
416 er
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
417 er
.Event
.WindowBufferSizeEvent
.dwSize
= ScreenBuffer
->ScreenBufferSize
;
419 ConioProcessInputEvent(Console
, &er
);
422 return STATUS_SUCCESS
;
426 ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff
, PSMALL_RECT UpdateRect
, PUINT ScrolledLines
)
428 /* If we hit bottom, slide the viewable screen */
429 if (++Buff
->CursorPosition
.Y
== Buff
->ScreenBufferSize
.Y
)
431 Buff
->CursorPosition
.Y
--;
432 if (++Buff
->VirtualY
== Buff
->ScreenBufferSize
.Y
)
437 ClearLineBuffer(Buff
);
438 if (UpdateRect
->Top
!= 0)
443 UpdateRect
->Left
= 0;
444 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
445 UpdateRect
->Bottom
= Buff
->CursorPosition
.Y
;
449 ConioWriteConsole(PCONSOLE Console
,
450 PTEXTMODE_SCREEN_BUFFER Buff
,
457 SMALL_RECT UpdateRect
;
458 SHORT CursorStartX
, CursorStartY
;
461 CursorStartX
= Buff
->CursorPosition
.X
;
462 CursorStartY
= Buff
->CursorPosition
.Y
;
463 UpdateRect
.Left
= Buff
->ScreenBufferSize
.X
;
464 UpdateRect
.Top
= Buff
->CursorPosition
.Y
;
465 UpdateRect
.Right
= -1;
466 UpdateRect
.Bottom
= Buff
->CursorPosition
.Y
;
469 for (i
= 0; i
< Length
; i
++)
472 * If we are in processed mode, interpret special characters and
473 * display them correctly. Otherwise, just put them into the buffer.
475 if (Buff
->Mode
& ENABLE_PROCESSED_OUTPUT
)
478 if (Buffer
[i
] == L
'\r')
480 Buff
->CursorPosition
.X
= 0;
481 UpdateRect
.Left
= min(UpdateRect
.Left
, Buff
->CursorPosition
.X
);
482 UpdateRect
.Right
= max(UpdateRect
.Right
, Buff
->CursorPosition
.X
);
486 else if (Buffer
[i
] == L
'\n')
488 Buff
->CursorPosition
.X
= 0;
489 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
493 else if (Buffer
[i
] == L
'\b')
495 /* Only handle BS if we're not on the first pos of the first line */
496 if (0 != Buff
->CursorPosition
.X
|| 0 != Buff
->CursorPosition
.Y
)
498 if (0 == Buff
->CursorPosition
.X
)
500 /* slide virtual position up */
501 Buff
->CursorPosition
.X
= Buff
->ScreenBufferSize
.X
- 1;
502 Buff
->CursorPosition
.Y
--;
503 UpdateRect
.Top
= min(UpdateRect
.Top
, Buff
->CursorPosition
.Y
);
507 Buff
->CursorPosition
.X
--;
509 Ptr
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
510 Ptr
->Char
.UnicodeChar
= L
' ';
511 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
512 UpdateRect
.Left
= min(UpdateRect
.Left
, Buff
->CursorPosition
.X
);
513 UpdateRect
.Right
= max(UpdateRect
.Right
, Buff
->CursorPosition
.X
);
518 else if (Buffer
[i
] == L
'\t')
522 UpdateRect
.Left
= min(UpdateRect
.Left
, Buff
->CursorPosition
.X
);
523 EndX
= (Buff
->CursorPosition
.X
+ TAB_WIDTH
) & ~(TAB_WIDTH
- 1);
524 EndX
= min(EndX
, (UINT
)Buff
->ScreenBufferSize
.X
);
525 Ptr
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
526 while (Buff
->CursorPosition
.X
< EndX
)
528 Ptr
->Char
.UnicodeChar
= L
' ';
529 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
531 Buff
->CursorPosition
.X
++;
533 UpdateRect
.Right
= max(UpdateRect
.Right
, Buff
->CursorPosition
.X
- 1);
534 if (Buff
->CursorPosition
.X
== Buff
->ScreenBufferSize
.X
)
536 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
538 Buff
->CursorPosition
.X
= 0;
539 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
543 Buff
->CursorPosition
.X
--;
549 // else if (Buffer[i] == L'\a')
551 // // FIXME: This MUST BE moved to the terminal emulator frontend!!
552 // DPRINT1("Bell\n");
553 // // SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0);
557 UpdateRect
.Left
= min(UpdateRect
.Left
, Buff
->CursorPosition
.X
);
558 UpdateRect
.Right
= max(UpdateRect
.Right
, Buff
->CursorPosition
.X
);
560 Ptr
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
561 Ptr
->Char
.UnicodeChar
= Buffer
[i
];
562 if (Attrib
) Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
564 Buff
->CursorPosition
.X
++;
565 if (Buff
->CursorPosition
.X
== Buff
->ScreenBufferSize
.X
)
567 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
569 Buff
->CursorPosition
.X
= 0;
570 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
574 Buff
->CursorPosition
.X
= CursorStartX
;
579 if (!ConioIsRectEmpty(&UpdateRect
) && (PCONSOLE_SCREEN_BUFFER
)Buff
== Console
->ActiveBuffer
)
581 TermWriteStream(Console
, &UpdateRect
, CursorStartX
, CursorStartY
,
582 ScrolledLines
, Buffer
, Length
);
585 return STATUS_SUCCESS
;
589 /* PUBLIC DRIVER APIS *********************************************************/
592 ConDrvReadConsoleOutput(IN PCONSOLE Console
,
593 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
595 OUT PCHAR_INFO CharInfo
/*Buffer*/,
596 IN PCOORD BufferSize
,
597 IN PCOORD BufferCoord
,
598 IN OUT PSMALL_RECT ReadRegion
)
600 PCHAR_INFO CurCharInfo
;
602 SMALL_RECT CapturedReadRegion
;
603 SMALL_RECT ScreenRect
;
609 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
||
610 BufferSize
== NULL
|| BufferCoord
== NULL
|| ReadRegion
== NULL
)
612 return STATUS_INVALID_PARAMETER
;
616 ASSERT(Console
== Buffer
->Header
.Console
);
618 CapturedReadRegion
= *ReadRegion
;
620 /* FIXME: Is this correct? */
621 CodePage
= Console
->OutputCodePage
;
623 SizeX
= min(BufferSize
->X
- BufferCoord
->X
, ConioRectWidth(&CapturedReadRegion
));
624 SizeY
= min(BufferSize
->Y
- BufferCoord
->Y
, ConioRectHeight(&CapturedReadRegion
));
625 CapturedReadRegion
.Right
= CapturedReadRegion
.Left
+ SizeX
;
626 CapturedReadRegion
.Bottom
= CapturedReadRegion
.Top
+ SizeY
;
628 ConioInitRect(&ScreenRect
, 0, 0, Buffer
->ScreenBufferSize
.Y
, Buffer
->ScreenBufferSize
.X
);
629 if (!ConioGetIntersection(&CapturedReadRegion
, &ScreenRect
, &CapturedReadRegion
))
631 return STATUS_SUCCESS
;
634 for (i
= 0, Y
= CapturedReadRegion
.Top
; Y
< CapturedReadRegion
.Bottom
; ++i
, ++Y
)
636 CurCharInfo
= CharInfo
+ (i
* BufferSize
->X
);
638 Ptr
= ConioCoordToPointer(Buffer
, CapturedReadRegion
.Left
, Y
);
639 for (X
= CapturedReadRegion
.Left
; X
< CapturedReadRegion
.Right
; ++X
)
643 CurCharInfo
->Char
.UnicodeChar
= Ptr
->Char
.UnicodeChar
;
647 // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
648 WideCharToMultiByte(CodePage
, 0, &Ptr
->Char
.UnicodeChar
, 1,
649 &CurCharInfo
->Char
.AsciiChar
, 1, NULL
, NULL
);
651 CurCharInfo
->Attributes
= Ptr
->Attributes
;
657 ReadRegion
->Left
= CapturedReadRegion
.Left
;
658 ReadRegion
->Top
= CapturedReadRegion
.Top
;
659 ReadRegion
->Right
= CapturedReadRegion
.Left
+ SizeX
- 1;
660 ReadRegion
->Bottom
= CapturedReadRegion
.Top
+ SizeY
- 1;
662 return STATUS_SUCCESS
;
666 ConDrvWriteConsoleOutput(IN PCONSOLE Console
,
667 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
669 IN PCHAR_INFO CharInfo
/*Buffer*/,
670 IN PCOORD BufferSize
,
671 IN PCOORD BufferCoord
,
672 IN OUT PSMALL_RECT WriteRegion
)
674 SHORT i
, X
, Y
, SizeX
, SizeY
;
675 SMALL_RECT ScreenBuffer
;
676 PCHAR_INFO CurCharInfo
;
677 SMALL_RECT CapturedWriteRegion
;
680 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
||
681 BufferSize
== NULL
|| BufferCoord
== NULL
|| WriteRegion
== NULL
)
683 return STATUS_INVALID_PARAMETER
;
687 ASSERT(Console
== Buffer
->Header
.Console
);
689 CapturedWriteRegion
= *WriteRegion
;
691 SizeX
= min(BufferSize
->X
- BufferCoord
->X
, ConioRectWidth(&CapturedWriteRegion
));
692 SizeY
= min(BufferSize
->Y
- BufferCoord
->Y
, ConioRectHeight(&CapturedWriteRegion
));
693 CapturedWriteRegion
.Right
= CapturedWriteRegion
.Left
+ SizeX
- 1;
694 CapturedWriteRegion
.Bottom
= CapturedWriteRegion
.Top
+ SizeY
- 1;
696 /* Make sure WriteRegion is inside the screen buffer */
697 ConioInitRect(&ScreenBuffer
, 0, 0, Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
698 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
701 * It is okay to have a WriteRegion completely outside
702 * the screen buffer. No data is written then.
704 return STATUS_SUCCESS
;
707 for (i
= 0, Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; i
++, Y
++)
709 CurCharInfo
= CharInfo
+ (i
+ BufferCoord
->Y
) * BufferSize
->X
+ BufferCoord
->X
;
711 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
712 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; X
++)
716 Ptr
->Char
.UnicodeChar
= CurCharInfo
->Char
.UnicodeChar
;
720 ConsoleAnsiCharToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
.AsciiChar
);
722 Ptr
->Attributes
= CurCharInfo
->Attributes
;
728 TermDrawRegion(Console
, &CapturedWriteRegion
);
730 WriteRegion
->Left
= CapturedWriteRegion
.Left
;
731 WriteRegion
->Top
= CapturedWriteRegion
.Top
;
732 WriteRegion
->Right
= CapturedWriteRegion
.Left
+ SizeX
- 1;
733 WriteRegion
->Bottom
= CapturedWriteRegion
.Top
+ SizeY
- 1;
735 return STATUS_SUCCESS
;
739 ConDrvWriteConsole(IN PCONSOLE Console
,
740 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
742 IN PVOID StringBuffer
,
743 IN ULONG NumCharsToWrite
,
744 OUT PULONG NumCharsWritten OPTIONAL
)
746 NTSTATUS Status
= STATUS_SUCCESS
;
747 PWCHAR Buffer
= NULL
;
751 if (Console
== NULL
|| ScreenBuffer
== NULL
/* || StringBuffer == NULL */)
752 return STATUS_INVALID_PARAMETER
;
754 /* Validity checks */
755 ASSERT(Console
== ScreenBuffer
->Header
.Console
);
756 ASSERT( (StringBuffer
!= NULL
&& NumCharsToWrite
>= 0) ||
757 (StringBuffer
== NULL
&& NumCharsToWrite
== 0) );
759 // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
760 if (Console
->PauseFlags
&& Console
->UnpauseEvent
!= NULL
)
762 return STATUS_PENDING
;
767 Buffer
= StringBuffer
;
771 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
775 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
778 MultiByteToWideChar(Console
->OutputCodePage
, 0,
781 (PWCHAR
)Buffer
, Length
);
785 Status
= STATUS_NO_MEMORY
;
791 if (NT_SUCCESS(Status
))
793 Status
= ConioWriteConsole(Console
,
798 if (NT_SUCCESS(Status
))
800 Written
= NumCharsToWrite
;
804 if (!Unicode
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
807 if (NumCharsWritten
) *NumCharsWritten
= Written
;
813 ConDrvReadConsoleOutputString(IN PCONSOLE Console
,
814 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
815 IN CODE_TYPE CodeType
,
816 OUT PVOID StringBuffer
,
817 IN ULONG NumCodesToRead
,
820 OUT PULONG CodesRead
)
828 if (Console
== NULL
|| Buffer
== NULL
||
829 ReadCoord
== NULL
|| EndCoord
== NULL
|| CodesRead
== NULL
)
831 return STATUS_INVALID_PARAMETER
;
834 /* Validity checks */
835 ASSERT(Console
== Buffer
->Header
.Console
);
836 ASSERT( (StringBuffer
!= NULL
&& NumCodesToRead
>= 0) ||
837 (StringBuffer
== NULL
&& NumCodesToRead
== 0) );
842 CodeSize
= sizeof(CHAR
);
846 CodeSize
= sizeof(WCHAR
);
850 CodeSize
= sizeof(WORD
);
854 return STATUS_INVALID_PARAMETER
;
857 ReadBuffer
= StringBuffer
;
859 Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
862 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
864 * If the number of attributes (resp. characters) to be read from extends
865 * beyond the end of the specified screen buffer row, attributes (resp.
866 * characters) are read from the next row. If the number of attributes
867 * (resp. characters) to be read from extends beyond the end of the console
868 * screen buffer, attributes (resp. characters) up to the end of the console
869 * screen buffer are read.
871 * TODO: Do NOT loop up to NumCodesToRead, but stop before
872 * if we are going to overflow...
874 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
875 for (i
= 0; i
< min(NumCodesToRead
, Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
); ++i
)
877 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
878 Ptr
= &Buffer
->Buffer
[Xpos
+ Ypos
* Buffer
->ScreenBufferSize
.X
];
883 ConsoleUnicodeCharToAnsiChar(Console
, (PCHAR
)ReadBuffer
, &Ptr
->Char
.UnicodeChar
);
887 *(PWCHAR
)ReadBuffer
= Ptr
->Char
.UnicodeChar
;
891 *(PWORD
)ReadBuffer
= Ptr
->Attributes
;
894 ReadBuffer
= (PVOID
)((ULONG_PTR
)ReadBuffer
+ CodeSize
);
899 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
904 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
913 // case CODE_UNICODE:
914 // *(PWCHAR)ReadBuffer = 0;
918 // *(PCHAR)ReadBuffer = 0;
921 // case CODE_ATTRIBUTE:
922 // *(PWORD)ReadBuffer = 0;
927 EndCoord
->Y
= (Ypos
- Buffer
->VirtualY
+ Buffer
->ScreenBufferSize
.Y
) % Buffer
->ScreenBufferSize
.Y
;
929 *CodesRead
= (ULONG
)((ULONG_PTR
)ReadBuffer
- (ULONG_PTR
)StringBuffer
) / CodeSize
;
932 return STATUS_SUCCESS
;
936 ConDrvWriteConsoleOutputString(IN PCONSOLE Console
,
937 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
938 IN CODE_TYPE CodeType
,
939 IN PVOID StringBuffer
,
940 IN ULONG NumCodesToWrite
,
941 IN PCOORD WriteCoord
/*,
943 OUT PULONG CodesWritten */)
945 NTSTATUS Status
= STATUS_SUCCESS
;
946 PVOID WriteBuffer
= NULL
;
947 PWCHAR tmpString
= NULL
;
948 DWORD X
, Y
, Length
; // , Written = 0;
950 SMALL_RECT UpdateRect
;
953 if (Console
== NULL
|| Buffer
== NULL
||
954 WriteCoord
== NULL
/* || EndCoord == NULL || CodesWritten == NULL */)
956 return STATUS_INVALID_PARAMETER
;
959 /* Validity checks */
960 ASSERT(Console
== Buffer
->Header
.Console
);
961 ASSERT( (StringBuffer
!= NULL
&& NumCodesToWrite
>= 0) ||
962 (StringBuffer
== NULL
&& NumCodesToWrite
== 0) );
967 CodeSize
= sizeof(CHAR
);
971 CodeSize
= sizeof(WCHAR
);
975 CodeSize
= sizeof(WORD
);
979 return STATUS_INVALID_PARAMETER
;
982 if (CodeType
== CODE_ASCII
)
984 /* Convert the ASCII string into Unicode before writing it to the console */
985 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
989 tmpString
= WriteBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
992 MultiByteToWideChar(Console
->OutputCodePage
, 0,
995 (PWCHAR
)WriteBuffer
, Length
);
999 Status
= STATUS_NO_MEMORY
;
1004 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
1005 WriteBuffer
= StringBuffer
;
1008 if (WriteBuffer
== NULL
|| !NT_SUCCESS(Status
)) goto Cleanup
;
1011 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1012 Length
= NumCodesToWrite
;
1013 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1014 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1018 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1019 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
1025 Ptr
->Char
.UnicodeChar
= *(PWCHAR
)WriteBuffer
;
1028 case CODE_ATTRIBUTE
:
1029 Ptr
->Attributes
= *(PWORD
)WriteBuffer
;
1032 WriteBuffer
= (PVOID
)((ULONG_PTR
)WriteBuffer
+ CodeSize
);
1036 if (++X
== Buffer
->ScreenBufferSize
.X
)
1040 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
1047 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1049 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1050 TermDrawRegion(Console
, &UpdateRect
);
1054 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1057 if (tmpString
) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString
);
1059 // CodesWritten = Written;
1064 ConDrvFillConsoleOutput(IN PCONSOLE Console
,
1065 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1066 IN CODE_TYPE CodeType
,
1068 IN ULONG NumCodesToWrite
,
1069 IN PCOORD WriteCoord
/*,
1070 OUT PULONG CodesWritten */)
1072 DWORD X
, Y
, Length
; // , Written = 0;
1074 SMALL_RECT UpdateRect
;
1076 if (Console
== NULL
|| Buffer
== NULL
|| Code
== NULL
||
1077 WriteCoord
== NULL
/* || CodesWritten == NULL */)
1079 return STATUS_INVALID_PARAMETER
;
1082 /* Validity check */
1083 ASSERT(Console
== Buffer
->Header
.Console
);
1089 /* On-place conversion from the ASCII char to the UNICODE char */
1090 ConsoleAnsiCharToUnicodeChar(Console
, &Code
->UnicodeChar
, &Code
->AsciiChar
);
1093 Code
= &Code
->UnicodeChar
;
1096 case CODE_ATTRIBUTE
:
1097 Code
= &Code
->Attribute
;
1101 if (CodeType
== CODE_ASCII
)
1103 /* On-place conversion from the ASCII char to the UNICODE char */
1104 // FIXME: What if Code points to an invalid memory zone ??
1105 ConsoleAnsiCharToUnicodeChar(Console
, (PWCHAR
)Code
, (PCHAR
)Code
);
1110 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1111 Length
= NumCodesToWrite
;
1112 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1113 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1117 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1118 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
1124 Ptr
->Char
.UnicodeChar
= *(PWCHAR
)Code
;
1127 case CODE_ATTRIBUTE
:
1128 Ptr
->Attributes
= *(PWORD
)Code
;
1134 if (++X
== Buffer
->ScreenBufferSize
.X
)
1138 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
1145 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1147 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1148 TermDrawRegion(Console
, &UpdateRect
);
1151 // CodesWritten = Written; // NumCodesToWrite;
1152 return STATUS_SUCCESS
;
1156 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console
,
1157 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1158 OUT PCONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo
)
1160 if (Console
== NULL
|| Buffer
== NULL
|| ScreenBufferInfo
== NULL
)
1161 return STATUS_INVALID_PARAMETER
;
1163 /* Validity check */
1164 ASSERT(Console
== Buffer
->Header
.Console
);
1166 ScreenBufferInfo
->dwSize
= Buffer
->ScreenBufferSize
;
1167 ScreenBufferInfo
->dwCursorPosition
= Buffer
->CursorPosition
;
1168 ScreenBufferInfo
->wAttributes
= Buffer
->ScreenDefaultAttrib
;
1169 ScreenBufferInfo
->srWindow
.Left
= Buffer
->ViewOrigin
.X
;
1170 ScreenBufferInfo
->srWindow
.Top
= Buffer
->ViewOrigin
.Y
;
1171 ScreenBufferInfo
->srWindow
.Right
= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1172 ScreenBufferInfo
->srWindow
.Bottom
= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1174 // FIXME: Refine the computation
1175 ScreenBufferInfo
->dwMaximumWindowSize
= Buffer
->ScreenBufferSize
;
1177 return STATUS_SUCCESS
;
1181 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console
,
1182 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1185 if (Console
== NULL
|| Buffer
== NULL
)
1186 return STATUS_INVALID_PARAMETER
;
1188 /* Validity check */
1189 ASSERT(Console
== Buffer
->Header
.Console
);
1191 Buffer
->ScreenDefaultAttrib
= Attribute
;
1192 return STATUS_SUCCESS
;
1196 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console
,
1197 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1202 if (Console
== NULL
|| Buffer
== NULL
|| Size
== NULL
)
1203 return STATUS_INVALID_PARAMETER
;
1205 /* Validity check */
1206 ASSERT(Console
== Buffer
->Header
.Console
);
1208 Status
= ConioResizeBuffer(Console
, Buffer
, *Size
);
1209 if (NT_SUCCESS(Status
)) TermResizeTerminal(Console
);
1215 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console
,
1216 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1218 IN PSMALL_RECT ScrollRectangle
,
1219 IN BOOLEAN UseClipRectangle
,
1220 IN PSMALL_RECT ClipRectangle OPTIONAL
,
1221 IN PCOORD DestinationOrigin
,
1222 IN CHAR_INFO FillChar
)
1224 COORD CapturedDestinationOrigin
;
1225 SMALL_RECT ScreenBuffer
;
1226 SMALL_RECT SrcRegion
;
1227 SMALL_RECT DstRegion
;
1228 SMALL_RECT UpdateRegion
;
1229 SMALL_RECT CapturedClipRectangle
;
1231 if (Console
== NULL
|| Buffer
== NULL
|| ScrollRectangle
== NULL
||
1232 (UseClipRectangle
? ClipRectangle
== NULL
: FALSE
) || DestinationOrigin
== NULL
)
1234 return STATUS_INVALID_PARAMETER
;
1237 /* Validity check */
1238 ASSERT(Console
== Buffer
->Header
.Console
);
1240 CapturedDestinationOrigin
= *DestinationOrigin
;
1242 /* Make sure the source rectangle is inside the screen buffer */
1243 ConioInitRect(&ScreenBuffer
, 0, 0, Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
1244 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, ScrollRectangle
))
1246 return STATUS_SUCCESS
;
1249 /* If the source was clipped on the left or top, adjust the destination accordingly */
1250 if (ScrollRectangle
->Left
< 0)
1252 CapturedDestinationOrigin
.X
-= ScrollRectangle
->Left
;
1254 if (ScrollRectangle
->Top
< 0)
1256 CapturedDestinationOrigin
.Y
-= ScrollRectangle
->Top
;
1259 if (UseClipRectangle
)
1261 CapturedClipRectangle
= *ClipRectangle
;
1262 if (!ConioGetIntersection(&CapturedClipRectangle
, &CapturedClipRectangle
, &ScreenBuffer
))
1264 return STATUS_SUCCESS
;
1269 CapturedClipRectangle
= ScreenBuffer
;
1272 ConioInitRect(&DstRegion
,
1273 CapturedDestinationOrigin
.Y
,
1274 CapturedDestinationOrigin
.X
,
1275 CapturedDestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1276 CapturedDestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1279 ConsoleAnsiCharToUnicodeChar(Console
, &FillChar
.Char
.UnicodeChar
, &FillChar
.Char
.AsciiChar
);
1281 ConioMoveRegion(Buffer
, &SrcRegion
, &DstRegion
, &CapturedClipRectangle
, FillChar
);
1283 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1285 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1286 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &CapturedClipRectangle
))
1288 /* Draw update region */
1289 TermDrawRegion(Console
, &UpdateRegion
);
1293 return STATUS_SUCCESS
;
1297 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console
,
1298 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1299 IN BOOLEAN Absolute
,
1300 IN PSMALL_RECT WindowRect
)
1302 SMALL_RECT CapturedWindowRect
;
1304 if (Console
== NULL
|| Buffer
== NULL
|| WindowRect
== NULL
)
1305 return STATUS_INVALID_PARAMETER
;
1307 /* Validity check */
1308 ASSERT(Console
== Buffer
->Header
.Console
);
1310 CapturedWindowRect
= *WindowRect
;
1312 if (Absolute
== FALSE
)
1314 /* Relative positions given. Transform them to absolute ones */
1315 CapturedWindowRect
.Left
+= Buffer
->ViewOrigin
.X
;
1316 CapturedWindowRect
.Top
+= Buffer
->ViewOrigin
.Y
;
1317 CapturedWindowRect
.Right
+= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1318 CapturedWindowRect
.Bottom
+= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1321 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1322 if ( (CapturedWindowRect
.Left
< 0) || (CapturedWindowRect
.Top
< 0) ||
1323 (CapturedWindowRect
.Right
>= Buffer
->ScreenBufferSize
.X
) ||
1324 (CapturedWindowRect
.Bottom
>= Buffer
->ScreenBufferSize
.Y
) ||
1325 (CapturedWindowRect
.Right
<= CapturedWindowRect
.Left
) ||
1326 (CapturedWindowRect
.Bottom
<= CapturedWindowRect
.Top
) )
1328 return STATUS_INVALID_PARAMETER
;
1331 Buffer
->ViewOrigin
.X
= CapturedWindowRect
.Left
;
1332 Buffer
->ViewOrigin
.Y
= CapturedWindowRect
.Top
;
1334 Buffer
->ViewSize
.X
= CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1;
1335 Buffer
->ViewSize
.Y
= CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1;
1337 // TermResizeTerminal(Console);
1339 return STATUS_SUCCESS
;