41b5ce72dc26c99162e259d2b7deb9d8d8c8a650
[reactos.git] / win32ss / user / winsrv / consrv / condrv / text.c
1 /*
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)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <consrv.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 #define TAB_WIDTH 8
20
21 /* PRIVATE FUNCTIONS **********************************************************/
22
23 CONSOLE_IO_OBJECT_TYPE
24 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This)
25 {
26 // return This->Header.Type;
27 return TEXTMODE_BUFFER;
28 }
29
30 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl =
31 {
32 TEXTMODE_BUFFER_GetType,
33 };
34
35
36 static VOID
37 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff);
38
39
40 NTSTATUS
41 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
42 IN OUT PCONSOLE Console,
43 IN SIZE_T Size);
44 VOID
45 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
46
47
48 NTSTATUS
49 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
50 IN OUT PCONSOLE Console,
51 IN PTEXTMODE_BUFFER_INFO TextModeInfo)
52 {
53 NTSTATUS Status = STATUS_SUCCESS;
54 PTEXTMODE_SCREEN_BUFFER NewBuffer = NULL;
55
56 if (Console == NULL || Buffer == NULL || TextModeInfo == NULL)
57 return STATUS_INVALID_PARAMETER;
58
59 *Buffer = NULL;
60
61 Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer,
62 Console,
63 sizeof(TEXTMODE_SCREEN_BUFFER));
64 if (!NT_SUCCESS(Status)) return Status;
65 NewBuffer->Header.Type = TEXTMODE_BUFFER;
66 NewBuffer->Vtbl = &TextVtbl;
67
68 NewBuffer->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
69 TextModeInfo->ScreenBufferSize.X *
70 TextModeInfo->ScreenBufferSize.Y *
71 sizeof(CHAR_INFO));
72 if (NewBuffer->Buffer == NULL)
73 {
74 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
75 return STATUS_INSUFFICIENT_RESOURCES;
76 }
77
78 NewBuffer->ScreenBufferSize = NewBuffer->OldScreenBufferSize
79 = TextModeInfo->ScreenBufferSize;
80 NewBuffer->ViewSize = NewBuffer->OldViewSize
81 = Console->ConsoleSize;
82
83 NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0;
84 NewBuffer->VirtualY = 0;
85
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);
89
90 NewBuffer->ScreenDefaultAttrib = TextModeInfo->ScreenAttrib;
91 NewBuffer->PopupDefaultAttrib = TextModeInfo->PopupAttrib;
92
93 /* Initialize buffer to be empty with default attributes */
94 for (NewBuffer->CursorPosition.Y = 0 ; NewBuffer->CursorPosition.Y < NewBuffer->ScreenBufferSize.Y; NewBuffer->CursorPosition.Y++)
95 {
96 ClearLineBuffer(NewBuffer);
97 }
98 NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0;
99
100 NewBuffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
101
102 *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer;
103 return STATUS_SUCCESS;
104 }
105
106 VOID
107 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
108 {
109 PTEXTMODE_SCREEN_BUFFER Buff = (PTEXTMODE_SCREEN_BUFFER)Buffer;
110
111 /*
112 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
113 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
114 */
115 Buffer->Header.Type = SCREEN_BUFFER;
116
117 ConsoleFreeHeap(Buff->Buffer);
118
119 CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
120 }
121
122
123 PCHAR_INFO
124 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
125 {
126 return &Buff->Buffer[((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) * Buff->ScreenBufferSize.X + X];
127 }
128
129 static VOID
130 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff)
131 {
132 PCHAR_INFO Ptr = ConioCoordToPointer(Buff, 0, Buff->CursorPosition.Y);
133 SHORT Pos;
134
135 for (Pos = 0; Pos < Buff->ScreenBufferSize.X; Pos++, Ptr++)
136 {
137 /* Fill the cell */
138 Ptr->Char.UnicodeChar = L' ';
139 Ptr->Attributes = Buff->ScreenDefaultAttrib;
140 }
141 }
142
143 static __inline BOOLEAN
144 ConioGetIntersection(OUT PSMALL_RECT Intersection,
145 IN PSMALL_RECT Rect1,
146 IN PSMALL_RECT Rect2)
147 {
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) )
154 {
155 /* The rectangles do not intersect */
156 ConioInitRect(Intersection, 0, -1, 0, -1);
157 return FALSE;
158 }
159
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 ));
165
166 return TRUE;
167 }
168
169 static __inline BOOLEAN
170 ConioGetUnion(OUT PSMALL_RECT Union,
171 IN PSMALL_RECT Rect1,
172 IN PSMALL_RECT Rect2)
173 {
174 if (ConioIsRectEmpty(Rect1))
175 {
176 if (ConioIsRectEmpty(Rect2))
177 {
178 ConioInitRect(Union, 0, -1, 0, -1);
179 return FALSE;
180 }
181 else
182 {
183 *Union = *Rect2;
184 }
185 }
186 else if (ConioIsRectEmpty(Rect2))
187 {
188 *Union = *Rect1;
189 }
190 else
191 {
192 ConioInitRect(Union,
193 min(Rect1->Top , Rect2->Top ),
194 min(Rect1->Left , Rect2->Left ),
195 max(Rect1->Bottom, Rect2->Bottom),
196 max(Rect1->Right , Rect2->Right ));
197 }
198
199 return TRUE;
200 }
201
202 static VOID
203 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff,
204 IN OUT PSMALL_RECT UpdateRect,
205 IN PCOORD Start,
206 IN UINT Length)
207 {
208 if (Buff->ScreenBufferSize.X <= Start->X + Length)
209 {
210 UpdateRect->Left = 0;
211 }
212 else
213 {
214 UpdateRect->Left = Start->X;
215 }
216 if (Buff->ScreenBufferSize.X <= Start->X + Length)
217 {
218 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
219 }
220 else
221 {
222 UpdateRect->Right = Start->X + Length - 1;
223 }
224 UpdateRect->Top = Start->Y;
225 UpdateRect->Bottom = Start->Y + (Start->X + Length - 1) / Buff->ScreenBufferSize.X;
226 if (Buff->ScreenBufferSize.Y <= UpdateRect->Bottom)
227 {
228 UpdateRect->Bottom = Buff->ScreenBufferSize.Y - 1;
229 }
230 }
231
232 /*
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.
235 */
236 static VOID
237 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
238 PSMALL_RECT SrcRegion,
239 PSMALL_RECT DstRegion,
240 PSMALL_RECT ClipRegion,
241 CHAR_INFO FillChar)
242 {
243 int Width = ConioRectWidth(SrcRegion);
244 int Height = ConioRectHeight(SrcRegion);
245 int SX, SY;
246 int DX, DY;
247 int XDelta, YDelta;
248 int i, j;
249
250 SY = SrcRegion->Top;
251 DY = DstRegion->Top;
252 YDelta = 1;
253 if (SY < DY)
254 {
255 /* Moving down: work from bottom up */
256 SY = SrcRegion->Bottom;
257 DY = DstRegion->Bottom;
258 YDelta = -1;
259 }
260 for (i = 0; i < Height; i++)
261 {
262 PCHAR_INFO SRow = ConioCoordToPointer(ScreenBuffer, 0, SY);
263 PCHAR_INFO DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
264
265 SX = SrcRegion->Left;
266 DX = DstRegion->Left;
267 XDelta = 1;
268 if (SX < DX)
269 {
270 /* Moving right: work from right to left */
271 SX = SrcRegion->Right;
272 DX = DstRegion->Right;
273 XDelta = -1;
274 }
275 for (j = 0; j < Width; j++)
276 {
277 CHAR_INFO Cell = SRow[SX];
278 if (SX >= ClipRegion->Left && SX <= ClipRegion->Right &&
279 SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
280 {
281 SRow[SX] = FillChar;
282 }
283 if (DX >= ClipRegion->Left && DX <= ClipRegion->Right &&
284 DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
285 {
286 DRow[DX] = Cell;
287 }
288 SX += XDelta;
289 DX += XDelta;
290 }
291 SY += YDelta;
292 DY += YDelta;
293 }
294 }
295
296 DWORD
297 ConioEffectiveCursorSize(PCONSOLE Console, DWORD Scale)
298 {
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->InsertMode ? !Console->LineInsertToggle : Console->LineInsertToggle))
302 return (Size * 2 <= Scale) ? (Size * 2) : (Size / 2);
303 return Size;
304 }
305
306 NTSTATUS
307 ConioResizeBuffer(PCONSOLE Console,
308 PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
309 COORD Size)
310 {
311 PCHAR_INFO Buffer;
312 DWORD Offset = 0;
313 PCHAR_INFO ptr;
314 WORD CurrentAttribute;
315 USHORT CurrentY;
316 PCHAR_INFO OldBuffer;
317 DWORD i;
318 DWORD diff;
319
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;
323
324 if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y)
325 {
326 // FIXME: Trigger a buffer resize event ??
327 return STATUS_SUCCESS;
328 }
329
330 if (Console->FixedSize)
331 {
332 /*
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.
336 */
337 ScreenBuffer->OldScreenBufferSize = Size;
338 return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS
339 }
340
341 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size.X * Size.Y * sizeof(CHAR_INFO));
342 if (!Buffer) return STATUS_NO_MEMORY;
343
344 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y);
345 OldBuffer = ScreenBuffer->Buffer;
346
347 for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++)
348 {
349 ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
350 if (Size.X <= ScreenBuffer->ScreenBufferSize.X)
351 {
352 /* Reduce size */
353 RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO));
354 Offset += Size.X;
355 }
356 else
357 {
358 /* Enlarge size */
359 RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO));
360 Offset += ScreenBuffer->ScreenBufferSize.X;
361
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;
366
367 diff = Size.X - ScreenBuffer->ScreenBufferSize.X;
368
369 /* Zero-out the new part of the buffer */
370 for (i = 0; i < diff; i++)
371 {
372 ptr = Buffer + Offset;
373 ptr->Char.UnicodeChar = L' ';
374 ptr->Attributes = CurrentAttribute;
375 ++Offset;
376 }
377 }
378 }
379
380 if (Size.Y > ScreenBuffer->ScreenBufferSize.Y)
381 {
382 diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y);
383
384 /* Zero-out the new part of the buffer */
385 for (i = 0; i < diff; i++)
386 {
387 ptr = Buffer + Offset;
388 ptr->Char.UnicodeChar = L' ';
389 ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib;
390 ++Offset;
391 }
392 }
393
394 (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer);
395 ConsoleFreeHeap(OldBuffer);
396 ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size;
397 ScreenBuffer->VirtualY = 0;
398
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;
408
409 /*
410 * Trigger a buffer resize event
411 */
412 if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT)
413 {
414 INPUT_RECORD er;
415
416 er.EventType = WINDOW_BUFFER_SIZE_EVENT;
417 er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize;
418
419 ConioProcessInputEvent(Console, &er);
420 }
421
422 return STATUS_SUCCESS;
423 }
424
425 static VOID
426 ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff, PSMALL_RECT UpdateRect, PUINT ScrolledLines)
427 {
428 /* If we hit bottom, slide the viewable screen */
429 if (++Buff->CursorPosition.Y == Buff->ScreenBufferSize.Y)
430 {
431 Buff->CursorPosition.Y--;
432 if (++Buff->VirtualY == Buff->ScreenBufferSize.Y)
433 {
434 Buff->VirtualY = 0;
435 }
436 (*ScrolledLines)++;
437 ClearLineBuffer(Buff);
438 if (UpdateRect->Top != 0)
439 {
440 UpdateRect->Top--;
441 }
442 }
443 UpdateRect->Left = 0;
444 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
445 UpdateRect->Bottom = Buff->CursorPosition.Y;
446 }
447
448 NTSTATUS
449 ConioWriteConsole(PCONSOLE Console,
450 PTEXTMODE_SCREEN_BUFFER Buff,
451 PWCHAR Buffer,
452 DWORD Length,
453 BOOL Attrib)
454 {
455 UINT i;
456 PCHAR_INFO Ptr;
457 SMALL_RECT UpdateRect;
458 SHORT CursorStartX, CursorStartY;
459 UINT ScrolledLines;
460
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;
467 ScrolledLines = 0;
468
469 for (i = 0; i < Length; i++)
470 {
471 /*
472 * If we are in processed mode, interpret special characters and
473 * display them correctly. Otherwise, just put them into the buffer.
474 */
475 if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
476 {
477 /* --- CR --- */
478 if (Buffer[i] == L'\r')
479 {
480 Buff->CursorPosition.X = 0;
481 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
482 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
483 continue;
484 }
485 /* --- LF --- */
486 else if (Buffer[i] == L'\n')
487 {
488 Buff->CursorPosition.X = 0;
489 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
490 continue;
491 }
492 /* --- BS --- */
493 else if (Buffer[i] == L'\b')
494 {
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)
497 {
498 if (0 == Buff->CursorPosition.X)
499 {
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);
504 }
505 else
506 {
507 Buff->CursorPosition.X--;
508 }
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);
514 }
515 continue;
516 }
517 /* --- TAB --- */
518 else if (Buffer[i] == L'\t')
519 {
520 UINT EndX;
521
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)
527 {
528 Ptr->Char.UnicodeChar = L' ';
529 Ptr->Attributes = Buff->ScreenDefaultAttrib;
530 ++Ptr;
531 Buff->CursorPosition.X++;
532 }
533 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1);
534 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
535 {
536 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
537 {
538 Buff->CursorPosition.X = 0;
539 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
540 }
541 else
542 {
543 Buff->CursorPosition.X--;
544 }
545 }
546 continue;
547 }
548 // /* --- BEL ---*/
549 // else if (Buffer[i] == L'\a')
550 // {
551 // // FIXME: This MUST BE moved to the terminal emulator frontend!!
552 // DPRINT1("Bell\n");
553 // // SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0);
554 // continue;
555 // }
556 }
557 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
558 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
559
560 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
561 Ptr->Char.UnicodeChar = Buffer[i];
562 if (Attrib) Ptr->Attributes = Buff->ScreenDefaultAttrib;
563
564 Buff->CursorPosition.X++;
565 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
566 {
567 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
568 {
569 Buff->CursorPosition.X = 0;
570 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
571 }
572 else
573 {
574 Buff->CursorPosition.X = CursorStartX;
575 }
576 }
577 }
578
579 if (!ConioIsRectEmpty(&UpdateRect) && (PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer)
580 {
581 TermWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY,
582 ScrolledLines, Buffer, Length);
583 }
584
585 return STATUS_SUCCESS;
586 }
587
588 NTSTATUS NTAPI
589 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console,
590 IN PTEXTMODE_SCREEN_BUFFER Buffer,
591 IN USHORT NewScreenAttrib,
592 IN USHORT NewPopupAttrib)
593 {
594 DWORD X, Y, Length;
595 PCHAR_INFO Ptr;
596
597 COORD TopLeft = {0};
598 ULONG NumCodesToWrite;
599 USHORT OldScreenAttrib;
600
601 if (Console == NULL || Buffer == NULL)
602 {
603 return STATUS_INVALID_PARAMETER;
604 }
605
606 /* Validity check */
607 ASSERT(Console == Buffer->Header.Console);
608
609 NumCodesToWrite = Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y;
610 OldScreenAttrib = Buffer->ScreenDefaultAttrib;
611
612 X = TopLeft.X;
613 Y = (TopLeft.Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
614 Length = NumCodesToWrite;
615
616 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
617 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
618
619 while (Length--)
620 {
621 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
622 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
623
624 /*
625 * Change the current colors only if they are the old ones.
626 */
627
628 /* Foreground color */
629 if ((Ptr->Attributes & 0x0F) == (OldScreenAttrib & 0x0F))
630 Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewScreenAttrib & 0x0F);
631
632 /* Background color */
633 if ((Ptr->Attributes & 0xF0) == (OldScreenAttrib & 0xF0))
634 Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewScreenAttrib & 0xF0);
635
636 // ++Ptr;
637
638 if (++X == Buffer->ScreenBufferSize.X)
639 {
640 X = 0;
641
642 if (++Y == Buffer->ScreenBufferSize.Y)
643 {
644 Y = 0;
645 }
646 }
647 }
648
649 /* Save foreground and background colors for both screen and popup */
650 Buffer->ScreenDefaultAttrib = (NewScreenAttrib & 0x00FF);
651 Buffer->PopupDefaultAttrib = (NewPopupAttrib & 0x00FF);
652
653 /* Refresh the display if needed */
654 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
655 {
656 SMALL_RECT UpdateRect;
657 ConioComputeUpdateRect(Buffer, &UpdateRect, &TopLeft, NumCodesToWrite);
658 TermDrawRegion(Console, &UpdateRect);
659 }
660
661 return STATUS_SUCCESS;
662 }
663
664
665 /* PUBLIC DRIVER APIS *********************************************************/
666
667 NTSTATUS NTAPI
668 ConDrvReadConsoleOutput(IN PCONSOLE Console,
669 IN PTEXTMODE_SCREEN_BUFFER Buffer,
670 IN BOOLEAN Unicode,
671 OUT PCHAR_INFO CharInfo/*Buffer*/,
672 IN PCOORD BufferSize,
673 IN PCOORD BufferCoord,
674 IN OUT PSMALL_RECT ReadRegion)
675 {
676 PCHAR_INFO CurCharInfo;
677 SHORT SizeX, SizeY;
678 SMALL_RECT CapturedReadRegion;
679 SMALL_RECT ScreenRect;
680 DWORD i;
681 PCHAR_INFO Ptr;
682 LONG X, Y;
683 UINT CodePage;
684
685 if (Console == NULL || Buffer == NULL || CharInfo == NULL ||
686 BufferSize == NULL || BufferCoord == NULL || ReadRegion == NULL)
687 {
688 return STATUS_INVALID_PARAMETER;
689 }
690
691 /* Validity check */
692 ASSERT(Console == Buffer->Header.Console);
693
694 CapturedReadRegion = *ReadRegion;
695
696 /* FIXME: Is this correct? */
697 CodePage = Console->OutputCodePage;
698
699 SizeX = min(BufferSize->X - BufferCoord->X, ConioRectWidth(&CapturedReadRegion));
700 SizeY = min(BufferSize->Y - BufferCoord->Y, ConioRectHeight(&CapturedReadRegion));
701 CapturedReadRegion.Right = CapturedReadRegion.Left + SizeX;
702 CapturedReadRegion.Bottom = CapturedReadRegion.Top + SizeY;
703
704 ConioInitRect(&ScreenRect, 0, 0, Buffer->ScreenBufferSize.Y, Buffer->ScreenBufferSize.X);
705 if (!ConioGetIntersection(&CapturedReadRegion, &ScreenRect, &CapturedReadRegion))
706 {
707 return STATUS_SUCCESS;
708 }
709
710 for (i = 0, Y = CapturedReadRegion.Top; Y < CapturedReadRegion.Bottom; ++i, ++Y)
711 {
712 CurCharInfo = CharInfo + (i * BufferSize->X);
713
714 Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y);
715 for (X = CapturedReadRegion.Left; X < CapturedReadRegion.Right; ++X)
716 {
717 if (Unicode)
718 {
719 CurCharInfo->Char.UnicodeChar = Ptr->Char.UnicodeChar;
720 }
721 else
722 {
723 // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
724 WideCharToMultiByte(CodePage, 0, &Ptr->Char.UnicodeChar, 1,
725 &CurCharInfo->Char.AsciiChar, 1, NULL, NULL);
726 }
727 CurCharInfo->Attributes = Ptr->Attributes;
728 ++Ptr;
729 ++CurCharInfo;
730 }
731 }
732
733 ReadRegion->Left = CapturedReadRegion.Left;
734 ReadRegion->Top = CapturedReadRegion.Top ;
735 ReadRegion->Right = CapturedReadRegion.Left + SizeX - 1;
736 ReadRegion->Bottom = CapturedReadRegion.Top + SizeY - 1;
737
738 return STATUS_SUCCESS;
739 }
740
741 NTSTATUS NTAPI
742 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
743 IN PTEXTMODE_SCREEN_BUFFER Buffer,
744 IN BOOLEAN Unicode,
745 IN PCHAR_INFO CharInfo/*Buffer*/,
746 IN PCOORD BufferSize,
747 IN PCOORD BufferCoord,
748 IN OUT PSMALL_RECT WriteRegion)
749 {
750 SHORT i, X, Y, SizeX, SizeY;
751 SMALL_RECT ScreenBuffer;
752 PCHAR_INFO CurCharInfo;
753 SMALL_RECT CapturedWriteRegion;
754 PCHAR_INFO Ptr;
755
756 if (Console == NULL || Buffer == NULL || CharInfo == NULL ||
757 BufferSize == NULL || BufferCoord == NULL || WriteRegion == NULL)
758 {
759 return STATUS_INVALID_PARAMETER;
760 }
761
762 /* Validity check */
763 ASSERT(Console == Buffer->Header.Console);
764
765 CapturedWriteRegion = *WriteRegion;
766
767 SizeX = min(BufferSize->X - BufferCoord->X, ConioRectWidth(&CapturedWriteRegion));
768 SizeY = min(BufferSize->Y - BufferCoord->Y, ConioRectHeight(&CapturedWriteRegion));
769 CapturedWriteRegion.Right = CapturedWriteRegion.Left + SizeX - 1;
770 CapturedWriteRegion.Bottom = CapturedWriteRegion.Top + SizeY - 1;
771
772 /* Make sure WriteRegion is inside the screen buffer */
773 ConioInitRect(&ScreenBuffer, 0, 0, Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
774 if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
775 {
776 /*
777 * It is okay to have a WriteRegion completely outside
778 * the screen buffer. No data is written then.
779 */
780 return STATUS_SUCCESS;
781 }
782
783 for (i = 0, Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; i++, Y++)
784 {
785 CurCharInfo = CharInfo + (i + BufferCoord->Y) * BufferSize->X + BufferCoord->X;
786
787 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
788 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; X++)
789 {
790 if (Unicode)
791 {
792 Ptr->Char.UnicodeChar = CurCharInfo->Char.UnicodeChar;
793 }
794 else
795 {
796 ConsoleAnsiCharToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char.AsciiChar);
797 }
798 Ptr->Attributes = CurCharInfo->Attributes;
799 ++Ptr;
800 ++CurCharInfo;
801 }
802 }
803
804 TermDrawRegion(Console, &CapturedWriteRegion);
805
806 WriteRegion->Left = CapturedWriteRegion.Left;
807 WriteRegion->Top = CapturedWriteRegion.Top ;
808 WriteRegion->Right = CapturedWriteRegion.Left + SizeX - 1;
809 WriteRegion->Bottom = CapturedWriteRegion.Top + SizeY - 1;
810
811 return STATUS_SUCCESS;
812 }
813
814 NTSTATUS NTAPI
815 ConDrvWriteConsole(IN PCONSOLE Console,
816 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
817 IN BOOLEAN Unicode,
818 IN PVOID StringBuffer,
819 IN ULONG NumCharsToWrite,
820 OUT PULONG NumCharsWritten OPTIONAL)
821 {
822 NTSTATUS Status = STATUS_SUCCESS;
823 PWCHAR Buffer = NULL;
824 ULONG Written = 0;
825 ULONG Length;
826
827 if (Console == NULL || ScreenBuffer == NULL /* || StringBuffer == NULL */)
828 return STATUS_INVALID_PARAMETER;
829
830 /* Validity checks */
831 ASSERT(Console == ScreenBuffer->Header.Console);
832 ASSERT( (StringBuffer != NULL && NumCharsToWrite > 0) ||
833 (StringBuffer == NULL && NumCharsToWrite == 0) );
834
835 // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
836 if (Console->PauseFlags && Console->UnpauseEvent != NULL)
837 {
838 return STATUS_PENDING;
839 }
840
841 if (Unicode)
842 {
843 Buffer = StringBuffer;
844 }
845 else
846 {
847 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
848 (PCHAR)StringBuffer,
849 NumCharsToWrite,
850 NULL, 0);
851 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
852 if (Buffer)
853 {
854 MultiByteToWideChar(Console->OutputCodePage, 0,
855 (PCHAR)StringBuffer,
856 NumCharsToWrite,
857 (PWCHAR)Buffer, Length);
858 }
859 else
860 {
861 Status = STATUS_NO_MEMORY;
862 }
863 }
864
865 if (Buffer)
866 {
867 if (NT_SUCCESS(Status))
868 {
869 Status = ConioWriteConsole(Console,
870 ScreenBuffer,
871 Buffer,
872 NumCharsToWrite,
873 TRUE);
874 if (NT_SUCCESS(Status))
875 {
876 Written = NumCharsToWrite;
877 }
878 }
879
880 if (!Unicode) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
881 }
882
883 if (NumCharsWritten) *NumCharsWritten = Written;
884
885 return Status;
886 }
887
888 NTSTATUS NTAPI
889 ConDrvReadConsoleOutputString(IN PCONSOLE Console,
890 IN PTEXTMODE_SCREEN_BUFFER Buffer,
891 IN CODE_TYPE CodeType,
892 OUT PVOID StringBuffer,
893 IN ULONG NumCodesToRead,
894 IN PCOORD ReadCoord,
895 OUT PCOORD EndCoord,
896 OUT PULONG CodesRead)
897 {
898 SHORT Xpos, Ypos;
899 PVOID ReadBuffer;
900 ULONG i;
901 ULONG CodeSize;
902 PCHAR_INFO Ptr;
903
904 if (Console == NULL || Buffer == NULL ||
905 ReadCoord == NULL || EndCoord == NULL || CodesRead == NULL)
906 {
907 return STATUS_INVALID_PARAMETER;
908 }
909
910 /* Validity checks */
911 ASSERT(Console == Buffer->Header.Console);
912 ASSERT( (StringBuffer != NULL && NumCodesToRead > 0) ||
913 (StringBuffer == NULL && NumCodesToRead == 0) );
914
915 switch (CodeType)
916 {
917 case CODE_ASCII:
918 CodeSize = sizeof(CHAR);
919 break;
920
921 case CODE_UNICODE:
922 CodeSize = sizeof(WCHAR);
923 break;
924
925 case CODE_ATTRIBUTE:
926 CodeSize = sizeof(WORD);
927 break;
928
929 default:
930 return STATUS_INVALID_PARAMETER;
931 }
932
933 ReadBuffer = StringBuffer;
934 Xpos = ReadCoord->X;
935 Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
936
937 /*
938 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
939 *
940 * If the number of attributes (resp. characters) to be read from extends
941 * beyond the end of the specified screen buffer row, attributes (resp.
942 * characters) are read from the next row. If the number of attributes
943 * (resp. characters) to be read from extends beyond the end of the console
944 * screen buffer, attributes (resp. characters) up to the end of the console
945 * screen buffer are read.
946 *
947 * TODO: Do NOT loop up to NumCodesToRead, but stop before
948 * if we are going to overflow...
949 */
950 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
951 for (i = 0; i < min(NumCodesToRead, Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y); ++i)
952 {
953 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
954 Ptr = &Buffer->Buffer[Xpos + Ypos * Buffer->ScreenBufferSize.X];
955
956 switch (CodeType)
957 {
958 case CODE_ASCII:
959 ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
960 break;
961
962 case CODE_UNICODE:
963 *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
964 break;
965
966 case CODE_ATTRIBUTE:
967 *(PWORD)ReadBuffer = Ptr->Attributes;
968 break;
969 }
970 ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
971 // ++Ptr;
972
973 Xpos++;
974
975 if (Xpos == Buffer->ScreenBufferSize.X)
976 {
977 Xpos = 0;
978 Ypos++;
979
980 if (Ypos == Buffer->ScreenBufferSize.Y)
981 {
982 Ypos = 0;
983 }
984 }
985 }
986
987 // switch (CodeType)
988 // {
989 // case CODE_UNICODE:
990 // *(PWCHAR)ReadBuffer = 0;
991 // break;
992
993 // case CODE_ASCII:
994 // *(PCHAR)ReadBuffer = 0;
995 // break;
996
997 // case CODE_ATTRIBUTE:
998 // *(PWORD)ReadBuffer = 0;
999 // break;
1000 // }
1001
1002 EndCoord->X = Xpos;
1003 EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
1004
1005 *CodesRead = (ULONG)((ULONG_PTR)ReadBuffer - (ULONG_PTR)StringBuffer) / CodeSize;
1006 // <= NumCodesToRead
1007
1008 return STATUS_SUCCESS;
1009 }
1010
1011 NTSTATUS NTAPI
1012 ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
1013 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1014 IN CODE_TYPE CodeType,
1015 IN PVOID StringBuffer,
1016 IN ULONG NumCodesToWrite,
1017 IN PCOORD WriteCoord /*,
1018 OUT PCOORD EndCoord,
1019 OUT PULONG CodesWritten */)
1020 {
1021 NTSTATUS Status = STATUS_SUCCESS;
1022 PVOID WriteBuffer = NULL;
1023 PWCHAR tmpString = NULL;
1024 DWORD X, Y, Length; // , Written = 0;
1025 ULONG CodeSize;
1026 PCHAR_INFO Ptr;
1027
1028 if (Console == NULL || Buffer == NULL ||
1029 WriteCoord == NULL /* || EndCoord == NULL || CodesWritten == NULL */)
1030 {
1031 return STATUS_INVALID_PARAMETER;
1032 }
1033
1034 /* Validity checks */
1035 ASSERT(Console == Buffer->Header.Console);
1036 ASSERT( (StringBuffer != NULL && NumCodesToWrite > 0) ||
1037 (StringBuffer == NULL && NumCodesToWrite == 0) );
1038
1039 switch (CodeType)
1040 {
1041 case CODE_ASCII:
1042 CodeSize = sizeof(CHAR);
1043 break;
1044
1045 case CODE_UNICODE:
1046 CodeSize = sizeof(WCHAR);
1047 break;
1048
1049 case CODE_ATTRIBUTE:
1050 CodeSize = sizeof(WORD);
1051 break;
1052
1053 default:
1054 return STATUS_INVALID_PARAMETER;
1055 }
1056
1057 if (CodeType == CODE_ASCII)
1058 {
1059 /* Convert the ASCII string into Unicode before writing it to the console */
1060 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
1061 (PCHAR)StringBuffer,
1062 NumCodesToWrite,
1063 NULL, 0);
1064 tmpString = WriteBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
1065 if (WriteBuffer)
1066 {
1067 MultiByteToWideChar(Console->OutputCodePage, 0,
1068 (PCHAR)StringBuffer,
1069 NumCodesToWrite,
1070 (PWCHAR)WriteBuffer, Length);
1071 }
1072 else
1073 {
1074 Status = STATUS_NO_MEMORY;
1075 }
1076 }
1077 else
1078 {
1079 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
1080 WriteBuffer = StringBuffer;
1081 }
1082
1083 if (WriteBuffer == NULL || !NT_SUCCESS(Status)) goto Cleanup;
1084
1085 X = WriteCoord->X;
1086 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1087 Length = NumCodesToWrite;
1088 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1089 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1090
1091 while (Length--)
1092 {
1093 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1094 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
1095
1096 switch (CodeType)
1097 {
1098 case CODE_ASCII:
1099 case CODE_UNICODE:
1100 Ptr->Char.UnicodeChar = *(PWCHAR)WriteBuffer;
1101 break;
1102
1103 case CODE_ATTRIBUTE:
1104 Ptr->Attributes = *(PWORD)WriteBuffer;
1105 break;
1106 }
1107 WriteBuffer = (PVOID)((ULONG_PTR)WriteBuffer + CodeSize);
1108 // ++Ptr;
1109
1110 // Written++;
1111 if (++X == Buffer->ScreenBufferSize.X)
1112 {
1113 X = 0;
1114
1115 if (++Y == Buffer->ScreenBufferSize.Y)
1116 {
1117 Y = 0;
1118 }
1119 }
1120 }
1121
1122 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1123 {
1124 SMALL_RECT UpdateRect;
1125 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1126 TermDrawRegion(Console, &UpdateRect);
1127 }
1128
1129 // EndCoord->X = X;
1130 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1131
1132 Cleanup:
1133 if (tmpString) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString);
1134
1135 // CodesWritten = Written;
1136 return Status;
1137 }
1138
1139 NTSTATUS NTAPI
1140 ConDrvFillConsoleOutput(IN PCONSOLE Console,
1141 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1142 IN CODE_TYPE CodeType,
1143 IN PVOID Code,
1144 IN ULONG NumCodesToWrite,
1145 IN PCOORD WriteCoord /*,
1146 OUT PULONG CodesWritten */)
1147 {
1148 DWORD X, Y, Length; // , Written = 0;
1149 PCHAR_INFO Ptr;
1150
1151 if (Console == NULL || Buffer == NULL || Code == NULL ||
1152 WriteCoord == NULL /* || CodesWritten == NULL */)
1153 {
1154 return STATUS_INVALID_PARAMETER;
1155 }
1156
1157 /* Validity check */
1158 ASSERT(Console == Buffer->Header.Console);
1159
1160 #if 0
1161 switch (CodeType)
1162 {
1163 case CODE_ASCII:
1164 /* On-place conversion from the ASCII char to the UNICODE char */
1165 ConsoleAnsiCharToUnicodeChar(Console, &Code->UnicodeChar, &Code->AsciiChar);
1166 /* Fall through */
1167 case CODE_UNICODE:
1168 Code = &Code->UnicodeChar;
1169 break;
1170
1171 case CODE_ATTRIBUTE:
1172 Code = &Code->Attribute;
1173 break;
1174 }
1175 #else
1176 if (CodeType == CODE_ASCII)
1177 {
1178 /* On-place conversion from the ASCII char to the UNICODE char */
1179 // FIXME: What if Code points to an invalid memory zone ??
1180 ConsoleAnsiCharToUnicodeChar(Console, (PWCHAR)Code, (PCHAR)Code);
1181 }
1182 #endif
1183
1184 X = WriteCoord->X;
1185 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1186 Length = NumCodesToWrite;
1187 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1188 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1189
1190 while (Length--)
1191 {
1192 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1193 Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
1194
1195 switch (CodeType)
1196 {
1197 case CODE_ASCII:
1198 case CODE_UNICODE:
1199 Ptr->Char.UnicodeChar = *(PWCHAR)Code;
1200 break;
1201
1202 case CODE_ATTRIBUTE:
1203 Ptr->Attributes = *(PWORD)Code;
1204 break;
1205 }
1206 // ++Ptr;
1207
1208 // Written++;
1209 if (++X == Buffer->ScreenBufferSize.X)
1210 {
1211 X = 0;
1212
1213 if (++Y == Buffer->ScreenBufferSize.Y)
1214 {
1215 Y = 0;
1216 }
1217 }
1218 }
1219
1220 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1221 {
1222 SMALL_RECT UpdateRect;
1223 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1224 TermDrawRegion(Console, &UpdateRect);
1225 }
1226
1227 // CodesWritten = Written; // NumCodesToWrite;
1228 return STATUS_SUCCESS;
1229 }
1230
1231 NTSTATUS NTAPI
1232 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console,
1233 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1234 OUT PCOORD ScreenBufferSize,
1235 OUT PCOORD CursorPosition,
1236 OUT PCOORD ViewOrigin,
1237 OUT PCOORD ViewSize,
1238 OUT PCOORD MaximumViewSize,
1239 OUT PWORD Attributes)
1240 {
1241 if (Console == NULL || Buffer == NULL || ScreenBufferSize == NULL ||
1242 CursorPosition == NULL || ViewOrigin == NULL || ViewSize == NULL ||
1243 MaximumViewSize == NULL || Attributes == NULL)
1244 {
1245 return STATUS_INVALID_PARAMETER;
1246 }
1247
1248 /* Validity check */
1249 ASSERT(Console == Buffer->Header.Console);
1250
1251 *ScreenBufferSize = Buffer->ScreenBufferSize;
1252 *CursorPosition = Buffer->CursorPosition;
1253 *ViewOrigin = Buffer->ViewOrigin;
1254 *ViewSize = Buffer->ViewSize;
1255 *Attributes = Buffer->ScreenDefaultAttrib;
1256
1257 // FIXME: Refine the computation
1258 *MaximumViewSize = Buffer->ScreenBufferSize;
1259
1260 return STATUS_SUCCESS;
1261 }
1262
1263 NTSTATUS NTAPI
1264 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
1265 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1266 IN WORD Attributes)
1267 {
1268 if (Console == NULL || Buffer == NULL)
1269 return STATUS_INVALID_PARAMETER;
1270
1271 /* Validity check */
1272 ASSERT(Console == Buffer->Header.Console);
1273
1274 Buffer->ScreenDefaultAttrib = Attributes;
1275 return STATUS_SUCCESS;
1276 }
1277
1278 NTSTATUS NTAPI
1279 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
1280 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1281 IN PCOORD Size)
1282 {
1283 NTSTATUS Status;
1284
1285 if (Console == NULL || Buffer == NULL || Size == NULL)
1286 return STATUS_INVALID_PARAMETER;
1287
1288 /* Validity check */
1289 ASSERT(Console == Buffer->Header.Console);
1290
1291 Status = ConioResizeBuffer(Console, Buffer, *Size);
1292 if (NT_SUCCESS(Status)) TermResizeTerminal(Console);
1293
1294 return Status;
1295 }
1296
1297 NTSTATUS NTAPI
1298 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
1299 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1300 IN BOOLEAN Unicode,
1301 IN PSMALL_RECT ScrollRectangle,
1302 IN BOOLEAN UseClipRectangle,
1303 IN PSMALL_RECT ClipRectangle OPTIONAL,
1304 IN PCOORD DestinationOrigin,
1305 IN CHAR_INFO FillChar)
1306 {
1307 COORD CapturedDestinationOrigin;
1308 SMALL_RECT ScreenBuffer;
1309 SMALL_RECT SrcRegion;
1310 SMALL_RECT DstRegion;
1311 SMALL_RECT UpdateRegion;
1312 SMALL_RECT CapturedClipRectangle;
1313
1314 if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
1315 (UseClipRectangle ? ClipRectangle == NULL : FALSE) || DestinationOrigin == NULL)
1316 {
1317 return STATUS_INVALID_PARAMETER;
1318 }
1319
1320 /* Validity check */
1321 ASSERT(Console == Buffer->Header.Console);
1322
1323 CapturedDestinationOrigin = *DestinationOrigin;
1324
1325 /* Make sure the source rectangle is inside the screen buffer */
1326 ConioInitRect(&ScreenBuffer, 0, 0, Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
1327 if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, ScrollRectangle))
1328 {
1329 return STATUS_SUCCESS;
1330 }
1331
1332 /* If the source was clipped on the left or top, adjust the destination accordingly */
1333 if (ScrollRectangle->Left < 0)
1334 {
1335 CapturedDestinationOrigin.X -= ScrollRectangle->Left;
1336 }
1337 if (ScrollRectangle->Top < 0)
1338 {
1339 CapturedDestinationOrigin.Y -= ScrollRectangle->Top;
1340 }
1341
1342 if (UseClipRectangle)
1343 {
1344 CapturedClipRectangle = *ClipRectangle;
1345 if (!ConioGetIntersection(&CapturedClipRectangle, &CapturedClipRectangle, &ScreenBuffer))
1346 {
1347 return STATUS_SUCCESS;
1348 }
1349 }
1350 else
1351 {
1352 CapturedClipRectangle = ScreenBuffer;
1353 }
1354
1355 ConioInitRect(&DstRegion,
1356 CapturedDestinationOrigin.Y,
1357 CapturedDestinationOrigin.X,
1358 CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
1359 CapturedDestinationOrigin.X + ConioRectWidth(&SrcRegion ) - 1);
1360
1361 if (!Unicode)
1362 ConsoleAnsiCharToUnicodeChar(Console, &FillChar.Char.UnicodeChar, &FillChar.Char.AsciiChar);
1363
1364 ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle, FillChar);
1365
1366 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1367 {
1368 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1369 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle))
1370 {
1371 /* Draw update region */
1372 TermDrawRegion(Console, &UpdateRegion);
1373 }
1374 }
1375
1376 return STATUS_SUCCESS;
1377 }
1378
1379 NTSTATUS NTAPI
1380 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
1381 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1382 IN BOOLEAN Absolute,
1383 IN PSMALL_RECT WindowRect)
1384 {
1385 SMALL_RECT CapturedWindowRect;
1386
1387 if (Console == NULL || Buffer == NULL || WindowRect == NULL)
1388 return STATUS_INVALID_PARAMETER;
1389
1390 /* Validity check */
1391 ASSERT(Console == Buffer->Header.Console);
1392
1393 CapturedWindowRect = *WindowRect;
1394
1395 if (Absolute == FALSE)
1396 {
1397 /* Relative positions given. Transform them to absolute ones */
1398 CapturedWindowRect.Left += Buffer->ViewOrigin.X;
1399 CapturedWindowRect.Top += Buffer->ViewOrigin.Y;
1400 CapturedWindowRect.Right += Buffer->ViewOrigin.X + Buffer->ViewSize.X - 1;
1401 CapturedWindowRect.Bottom += Buffer->ViewOrigin.Y + Buffer->ViewSize.Y - 1;
1402 }
1403
1404 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1405 if ( (CapturedWindowRect.Left < 0) || (CapturedWindowRect.Top < 0) ||
1406 (CapturedWindowRect.Right >= Buffer->ScreenBufferSize.X) ||
1407 (CapturedWindowRect.Bottom >= Buffer->ScreenBufferSize.Y) ||
1408 (CapturedWindowRect.Right <= CapturedWindowRect.Left) ||
1409 (CapturedWindowRect.Bottom <= CapturedWindowRect.Top) )
1410 {
1411 return STATUS_INVALID_PARAMETER;
1412 }
1413
1414 Buffer->ViewOrigin.X = CapturedWindowRect.Left;
1415 Buffer->ViewOrigin.Y = CapturedWindowRect.Top;
1416
1417 Buffer->ViewSize.X = CapturedWindowRect.Right - CapturedWindowRect.Left + 1;
1418 Buffer->ViewSize.Y = CapturedWindowRect.Bottom - CapturedWindowRect.Top + 1;
1419
1420 // TermResizeTerminal(Console);
1421
1422 return STATUS_SUCCESS;
1423 }
1424
1425 /* EOF */