[CONSRV] Fix the definitions of the Console[Input|Output]UnicodeToAnsiChar() and...
[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 #define COMMON_LEAD_TRAIL (COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE)
18
19 /* GLOBALS ********************************************************************/
20
21 /*
22 * From MSDN:
23 * "The lpMultiByteStr and lpWideCharStr pointers must not be the same.
24 * If they are the same, the function fails, and GetLastError returns
25 * ERROR_INVALID_PARAMETER."
26 */
27 #define ConsoleOutputUnicodeToAnsiChar(Console, dChar, sWChar) \
28 do { \
29 ASSERT((ULONG_PTR)(dChar) != (ULONG_PTR)(sWChar)); \
30 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL); \
31 } while (0)
32
33 #define ConsoleOutputAnsiToUnicodeChar(Console, dWChar, sChar) \
34 do { \
35 ASSERT((ULONG_PTR)(dWChar) != (ULONG_PTR)(sChar)); \
36 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1); \
37 } while (0)
38
39 /* PRIVATE FUNCTIONS **********************************************************/
40
41 CONSOLE_IO_OBJECT_TYPE
42 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This)
43 {
44 // return This->Header.Type;
45 return TEXTMODE_BUFFER;
46 }
47
48 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl =
49 {
50 TEXTMODE_BUFFER_GetType,
51 };
52
53
54 /*static*/ VOID
55 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff);
56
57
58 NTSTATUS
59 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
60 IN PCONSOLE Console,
61 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl,
62 IN SIZE_T Size);
63 VOID
64 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
65
66
67 NTSTATUS
68 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
69 IN PCONSOLE Console,
70 IN HANDLE ProcessHandle,
71 IN PTEXTMODE_BUFFER_INFO TextModeInfo)
72 {
73 NTSTATUS Status = STATUS_SUCCESS;
74 PTEXTMODE_SCREEN_BUFFER NewBuffer = NULL;
75
76 UNREFERENCED_PARAMETER(ProcessHandle);
77
78 if (Console == NULL || Buffer == NULL || TextModeInfo == NULL)
79 return STATUS_INVALID_PARAMETER;
80
81 *Buffer = NULL;
82
83 Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer,
84 Console,
85 &TextVtbl,
86 sizeof(TEXTMODE_SCREEN_BUFFER));
87 if (!NT_SUCCESS(Status)) return Status;
88 NewBuffer->Header.Type = TEXTMODE_BUFFER;
89
90 NewBuffer->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
91 TextModeInfo->ScreenBufferSize.X *
92 TextModeInfo->ScreenBufferSize.Y *
93 sizeof(CHAR_INFO));
94 if (NewBuffer->Buffer == NULL)
95 {
96 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
97 return STATUS_INSUFFICIENT_RESOURCES;
98 }
99
100 NewBuffer->ScreenBufferSize = NewBuffer->OldScreenBufferSize
101 = TextModeInfo->ScreenBufferSize;
102 NewBuffer->ViewSize = NewBuffer->OldViewSize
103 = Console->ConsoleSize;
104
105 NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0;
106 NewBuffer->VirtualY = 0;
107
108 NewBuffer->CursorBlinkOn = NewBuffer->ForceCursorOff = FALSE;
109 NewBuffer->CursorInfo.bVisible = (TextModeInfo->IsCursorVisible && (TextModeInfo->CursorSize != 0));
110 NewBuffer->CursorInfo.dwSize = min(max(TextModeInfo->CursorSize, 0), 100);
111
112 NewBuffer->ScreenDefaultAttrib = TextModeInfo->ScreenAttrib;
113 NewBuffer->PopupDefaultAttrib = TextModeInfo->PopupAttrib;
114
115 /* Initialize buffer to be empty with default attributes */
116 for (NewBuffer->CursorPosition.Y = 0 ; NewBuffer->CursorPosition.Y < NewBuffer->ScreenBufferSize.Y; NewBuffer->CursorPosition.Y++)
117 {
118 ClearLineBuffer(NewBuffer);
119 }
120 NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0;
121
122 NewBuffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
123
124 *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer;
125 return STATUS_SUCCESS;
126 }
127
128 VOID
129 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
130 {
131 PTEXTMODE_SCREEN_BUFFER Buff = (PTEXTMODE_SCREEN_BUFFER)Buffer;
132
133 /*
134 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
135 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
136 */
137 Buffer->Header.Type = SCREEN_BUFFER;
138
139 ConsoleFreeHeap(Buff->Buffer);
140
141 CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
142 }
143
144
145 PCHAR_INFO
146 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
147 {
148 return &Buff->Buffer[((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) * Buff->ScreenBufferSize.X + X];
149 }
150
151 /*static*/ VOID
152 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff)
153 {
154 PCHAR_INFO Ptr = ConioCoordToPointer(Buff, 0, Buff->CursorPosition.Y);
155 SHORT Pos;
156
157 for (Pos = 0; Pos < Buff->ScreenBufferSize.X; Pos++, Ptr++)
158 {
159 /* Fill the cell */
160 Ptr->Char.UnicodeChar = L' ';
161 Ptr->Attributes = Buff->ScreenDefaultAttrib;
162 }
163 }
164
165 static VOID
166 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff,
167 IN OUT PSMALL_RECT UpdateRect,
168 IN PCOORD Start,
169 IN UINT Length)
170 {
171 if ((UINT)Buff->ScreenBufferSize.X <= Start->X + Length)
172 {
173 UpdateRect->Left = 0;
174 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
175 }
176 else
177 {
178 UpdateRect->Left = Start->X;
179 UpdateRect->Right = Start->X + Length - 1;
180 }
181 UpdateRect->Top = Start->Y;
182 UpdateRect->Bottom = Start->Y + (Start->X + Length - 1) / Buff->ScreenBufferSize.X;
183 if (Buff->ScreenBufferSize.Y <= UpdateRect->Bottom)
184 {
185 UpdateRect->Bottom = Buff->ScreenBufferSize.Y - 1;
186 }
187 }
188
189 /*
190 * Move from one rectangle to another. We must be careful about the order that
191 * this is done, to avoid overwriting parts of the source before they are moved.
192 */
193 static VOID
194 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
195 PSMALL_RECT SrcRegion,
196 PSMALL_RECT DstRegion,
197 PSMALL_RECT ClipRegion,
198 CHAR_INFO FillChar)
199 {
200 int Width = ConioRectWidth(SrcRegion);
201 int Height = ConioRectHeight(SrcRegion);
202 int SX, SY;
203 int DX, DY;
204 int XDelta, YDelta;
205 int i, j;
206
207 SY = SrcRegion->Top;
208 DY = DstRegion->Top;
209 YDelta = 1;
210 if (SY < DY)
211 {
212 /* Moving down: work from bottom up */
213 SY = SrcRegion->Bottom;
214 DY = DstRegion->Bottom;
215 YDelta = -1;
216 }
217 for (i = 0; i < Height; i++)
218 {
219 PCHAR_INFO SRow = ConioCoordToPointer(ScreenBuffer, 0, SY);
220 PCHAR_INFO DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
221
222 SX = SrcRegion->Left;
223 DX = DstRegion->Left;
224 XDelta = 1;
225 if (SX < DX)
226 {
227 /* Moving right: work from right to left */
228 SX = SrcRegion->Right;
229 DX = DstRegion->Right;
230 XDelta = -1;
231 }
232 for (j = 0; j < Width; j++)
233 {
234 CHAR_INFO Cell = SRow[SX];
235 if (SX >= ClipRegion->Left && SX <= ClipRegion->Right &&
236 SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
237 {
238 SRow[SX] = FillChar;
239 }
240 if (DX >= ClipRegion->Left && DX <= ClipRegion->Right &&
241 DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
242 {
243 DRow[DX] = Cell;
244 }
245 SX += XDelta;
246 DX += XDelta;
247 }
248 SY += YDelta;
249 DY += YDelta;
250 }
251 }
252
253 // FIXME!
254 NTSTATUS NTAPI
255 ConDrvWriteConsoleInput(IN PCONSOLE Console,
256 IN PCONSOLE_INPUT_BUFFER InputBuffer,
257 IN BOOLEAN AppendToEnd,
258 IN PINPUT_RECORD InputRecord,
259 IN ULONG NumEventsToWrite,
260 OUT PULONG NumEventsWritten OPTIONAL);
261
262 NTSTATUS
263 ConioResizeBuffer(PCONSOLE Console,
264 PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
265 COORD Size)
266 {
267 PCHAR_INFO Buffer;
268 DWORD Offset = 0;
269 PCHAR_INFO ptr;
270 WORD CurrentAttribute;
271 USHORT CurrentY;
272 PCHAR_INFO OldBuffer;
273 DWORD i;
274 DWORD diff;
275
276 /* Buffer size is not allowed to be smaller than the view size */
277 if (Size.X < ScreenBuffer->ViewSize.X || Size.Y < ScreenBuffer->ViewSize.Y)
278 return STATUS_INVALID_PARAMETER;
279
280 if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y)
281 {
282 // FIXME: Trigger a buffer resize event ??
283 return STATUS_SUCCESS;
284 }
285
286 if (Console->FixedSize)
287 {
288 /*
289 * The console is in fixed-size mode, so we cannot resize anything
290 * at the moment. However, keep those settings somewhere so that
291 * we can try to set them up when we will be allowed to do so.
292 */
293 ScreenBuffer->OldScreenBufferSize = Size;
294 return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS
295 }
296
297 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size.X * Size.Y * sizeof(CHAR_INFO));
298 if (!Buffer) return STATUS_NO_MEMORY;
299
300 DPRINT("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y);
301 OldBuffer = ScreenBuffer->Buffer;
302
303 for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++)
304 {
305 ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
306 if (Size.X <= ScreenBuffer->ScreenBufferSize.X)
307 {
308 /* Reduce size */
309 RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO));
310 Offset += Size.X;
311 }
312 else
313 {
314 /* Enlarge size */
315 RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO));
316 Offset += ScreenBuffer->ScreenBufferSize.X;
317
318 /* The attribute to be used is the one of the last cell of the current line */
319 CurrentAttribute = ConioCoordToPointer(ScreenBuffer,
320 ScreenBuffer->ScreenBufferSize.X - 1,
321 CurrentY)->Attributes;
322
323 diff = Size.X - ScreenBuffer->ScreenBufferSize.X;
324
325 /* Zero-out the new part of the buffer */
326 for (i = 0; i < diff; i++)
327 {
328 ptr = Buffer + Offset;
329 ptr->Char.UnicodeChar = L' ';
330 ptr->Attributes = CurrentAttribute;
331 ++Offset;
332 }
333 }
334 }
335
336 if (Size.Y > ScreenBuffer->ScreenBufferSize.Y)
337 {
338 diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y);
339
340 /* Zero-out the new part of the buffer */
341 for (i = 0; i < diff; i++)
342 {
343 ptr = Buffer + Offset;
344 ptr->Char.UnicodeChar = L' ';
345 ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib;
346 ++Offset;
347 }
348 }
349
350 (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer);
351 ConsoleFreeHeap(OldBuffer);
352 ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size;
353 ScreenBuffer->VirtualY = 0;
354
355 /* Ensure cursor and window are within buffer */
356 if (ScreenBuffer->CursorPosition.X >= Size.X)
357 ScreenBuffer->CursorPosition.X = Size.X - 1;
358 if (ScreenBuffer->CursorPosition.Y >= Size.Y)
359 ScreenBuffer->CursorPosition.Y = Size.Y - 1;
360 if (ScreenBuffer->ViewOrigin.X > Size.X - ScreenBuffer->ViewSize.X)
361 ScreenBuffer->ViewOrigin.X = Size.X - ScreenBuffer->ViewSize.X;
362 if (ScreenBuffer->ViewOrigin.Y > Size.Y - ScreenBuffer->ViewSize.Y)
363 ScreenBuffer->ViewOrigin.Y = Size.Y - ScreenBuffer->ViewSize.Y;
364
365 /*
366 * Trigger a buffer resize event
367 */
368 if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT)
369 {
370 ULONG NumEventsWritten;
371 INPUT_RECORD er;
372
373 er.EventType = WINDOW_BUFFER_SIZE_EVENT;
374 er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize;
375
376 // ConioProcessInputEvent(Console, &er);
377 ConDrvWriteConsoleInput(Console,
378 &Console->InputBuffer,
379 TRUE,
380 &er,
381 1,
382 &NumEventsWritten);
383 }
384
385 return STATUS_SUCCESS;
386 }
387
388 NTSTATUS NTAPI
389 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console,
390 IN PTEXTMODE_SCREEN_BUFFER Buffer,
391 IN USHORT NewScreenAttrib,
392 IN USHORT NewPopupAttrib)
393 {
394 ULONG X, Y, Length;
395 PCHAR_INFO Ptr;
396
397 COORD TopLeft = {0};
398 ULONG NumCodesToWrite;
399 USHORT OldScreenAttrib, OldPopupAttrib;
400
401 if (Console == NULL || Buffer == NULL)
402 {
403 return STATUS_INVALID_PARAMETER;
404 }
405
406 /* Validity check */
407 ASSERT(Console == Buffer->Header.Console);
408
409 NumCodesToWrite = Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y;
410 OldScreenAttrib = Buffer->ScreenDefaultAttrib;
411 OldPopupAttrib = Buffer->PopupDefaultAttrib;
412
413 X = TopLeft.X;
414 Y = (TopLeft.Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
415 Length = NumCodesToWrite;
416
417 while (Length--)
418 {
419 Ptr = ConioCoordToPointer(Buffer, X, Y);
420
421 /*
422 * Change the current colors only if they are the old ones.
423 */
424
425 /* Foreground color */
426 if ((Ptr->Attributes & 0x0F) == (OldScreenAttrib & 0x0F))
427 Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewScreenAttrib & 0x0F);
428 if ((Ptr->Attributes & 0x0F) == (OldPopupAttrib & 0x0F))
429 Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewPopupAttrib & 0x0F);
430
431 /* Background color */
432 if ((Ptr->Attributes & 0xF0) == (OldScreenAttrib & 0xF0))
433 Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewScreenAttrib & 0xF0);
434 if ((Ptr->Attributes & 0xF0) == (OldPopupAttrib & 0xF0))
435 Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewPopupAttrib & 0xF0);
436
437 // ++Ptr;
438
439 if (++X == Buffer->ScreenBufferSize.X)
440 {
441 X = 0;
442
443 if (++Y == Buffer->ScreenBufferSize.Y)
444 {
445 Y = 0;
446 }
447 }
448 }
449
450 /* Save foreground and background colors for both screen and popup */
451 Buffer->ScreenDefaultAttrib = (NewScreenAttrib & 0x00FF);
452 Buffer->PopupDefaultAttrib = (NewPopupAttrib & 0x00FF);
453
454 /* Refresh the display if needed */
455 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
456 {
457 SMALL_RECT UpdateRect;
458 ConioComputeUpdateRect(Buffer, &UpdateRect, &TopLeft, NumCodesToWrite);
459 TermDrawRegion(Console, &UpdateRect);
460 }
461
462 return STATUS_SUCCESS;
463 }
464
465
466 /* PUBLIC DRIVER APIS *********************************************************/
467
468 NTSTATUS NTAPI
469 ConDrvReadConsoleOutput(IN PCONSOLE Console,
470 IN PTEXTMODE_SCREEN_BUFFER Buffer,
471 IN BOOLEAN Unicode,
472 OUT PCHAR_INFO CharInfo/*Buffer*/,
473 IN OUT PSMALL_RECT ReadRegion)
474 {
475 SHORT X, Y;
476 SMALL_RECT ScreenBuffer;
477 PCHAR_INFO CurCharInfo;
478 SMALL_RECT CapturedReadRegion;
479 PCHAR_INFO Ptr;
480
481 if (Console == NULL || Buffer == NULL || CharInfo == NULL || ReadRegion == NULL)
482 {
483 return STATUS_INVALID_PARAMETER;
484 }
485
486 /* Validity check */
487 ASSERT(Console == Buffer->Header.Console);
488
489 CapturedReadRegion = *ReadRegion;
490
491 /* Make sure ReadRegion is inside the screen buffer */
492 ConioInitRect(&ScreenBuffer, 0, 0,
493 Buffer->ScreenBufferSize.Y - 1,
494 Buffer->ScreenBufferSize.X - 1);
495 if (!ConioGetIntersection(&CapturedReadRegion, &ScreenBuffer, &CapturedReadRegion))
496 {
497 /*
498 * It is okay to have a ReadRegion completely outside
499 * the screen buffer. No data is read then.
500 */
501 return STATUS_SUCCESS;
502 }
503
504 CurCharInfo = CharInfo;
505
506 for (Y = CapturedReadRegion.Top; Y <= CapturedReadRegion.Bottom; ++Y)
507 {
508 Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y);
509 for (X = CapturedReadRegion.Left; X <= CapturedReadRegion.Right; ++X)
510 {
511 if (Unicode)
512 {
513 CurCharInfo->Char.UnicodeChar = Ptr->Char.UnicodeChar;
514 }
515 else
516 {
517 // ConsoleOutputUnicodeToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
518 WideCharToMultiByte(Console->OutputCodePage, 0, &Ptr->Char.UnicodeChar, 1,
519 &CurCharInfo->Char.AsciiChar, 1, NULL, NULL);
520 }
521 CurCharInfo->Attributes = (Ptr->Attributes & ~COMMON_LEAD_TRAIL);
522 ++Ptr;
523 ++CurCharInfo;
524 }
525 }
526
527 *ReadRegion = CapturedReadRegion;
528
529 return STATUS_SUCCESS;
530 }
531
532 NTSTATUS NTAPI
533 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
534 IN PTEXTMODE_SCREEN_BUFFER Buffer,
535 IN BOOLEAN Unicode,
536 IN PCHAR_INFO CharInfo/*Buffer*/,
537 IN OUT PSMALL_RECT WriteRegion)
538 {
539 SHORT X, Y;
540 SMALL_RECT ScreenBuffer;
541 PCHAR_INFO CurCharInfo;
542 SMALL_RECT CapturedWriteRegion;
543 PCHAR_INFO Ptr;
544
545 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
546 {
547 return STATUS_INVALID_PARAMETER;
548 }
549
550 /* Validity check */
551 ASSERT(Console == Buffer->Header.Console);
552
553 CapturedWriteRegion = *WriteRegion;
554
555 /* Make sure WriteRegion is inside the screen buffer */
556 ConioInitRect(&ScreenBuffer, 0, 0,
557 Buffer->ScreenBufferSize.Y - 1,
558 Buffer->ScreenBufferSize.X - 1);
559 if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
560 {
561 /*
562 * It is okay to have a WriteRegion completely outside
563 * the screen buffer. No data is written then.
564 */
565 return STATUS_SUCCESS;
566 }
567
568 CurCharInfo = CharInfo;
569
570 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
571 {
572 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
573 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
574 {
575 if (Unicode)
576 {
577 Ptr->Char.UnicodeChar = CurCharInfo->Char.UnicodeChar;
578 }
579 else
580 {
581 ConsoleOutputAnsiToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char.AsciiChar);
582 }
583 Ptr->Attributes = CurCharInfo->Attributes;
584 ++Ptr;
585 ++CurCharInfo;
586 }
587 }
588
589 TermDrawRegion(Console, &CapturedWriteRegion);
590
591 *WriteRegion = CapturedWriteRegion;
592
593 return STATUS_SUCCESS;
594 }
595
596 /*
597 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
598 * FIXME: This function MUST be moved into consrv/conoutput.c because only
599 * consrv knows how to manipulate VDM screenbuffers.
600 */
601 NTSTATUS NTAPI
602 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
603 IN PTEXTMODE_SCREEN_BUFFER Buffer,
604 IN PCHAR_CELL CharInfo/*Buffer*/,
605 IN COORD CharInfoSize,
606 IN PSMALL_RECT WriteRegion)
607 {
608 SHORT X, Y;
609 SMALL_RECT ScreenBuffer;
610 PCHAR_CELL CurCharInfo;
611 SMALL_RECT CapturedWriteRegion;
612 PCHAR_INFO Ptr;
613
614 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
615 {
616 return STATUS_INVALID_PARAMETER;
617 }
618
619 /* Validity check */
620 ASSERT(Console == Buffer->Header.Console);
621
622 CapturedWriteRegion = *WriteRegion;
623
624 /* Make sure WriteRegion is inside the screen buffer */
625 ConioInitRect(&ScreenBuffer, 0, 0,
626 Buffer->ScreenBufferSize.Y - 1,
627 Buffer->ScreenBufferSize.X - 1);
628 if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
629 {
630 /*
631 * It is okay to have a WriteRegion completely outside
632 * the screen buffer. No data is written then.
633 */
634 return STATUS_SUCCESS;
635 }
636
637 // CurCharInfo = CharInfo;
638
639 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
640 {
641 /**/CurCharInfo = CharInfo + Y * CharInfoSize.X + CapturedWriteRegion.Left;/**/
642
643 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
644 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
645 {
646 ConsoleOutputAnsiToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char);
647 Ptr->Attributes = CurCharInfo->Attributes;
648 ++Ptr;
649 ++CurCharInfo;
650 }
651 }
652
653 return STATUS_SUCCESS;
654 }
655
656 NTSTATUS NTAPI
657 ConDrvWriteConsole(IN PCONSOLE Console,
658 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
659 IN BOOLEAN Unicode,
660 IN PVOID StringBuffer,
661 IN ULONG NumCharsToWrite,
662 OUT PULONG NumCharsWritten OPTIONAL)
663 {
664 NTSTATUS Status = STATUS_SUCCESS;
665 PWCHAR Buffer = NULL;
666 ULONG Written = 0;
667 ULONG Length;
668
669 if (Console == NULL || ScreenBuffer == NULL /* || StringBuffer == NULL */)
670 return STATUS_INVALID_PARAMETER;
671
672 /* Validity checks */
673 ASSERT(Console == ScreenBuffer->Header.Console);
674 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCharsToWrite == 0));
675
676 /* Stop here if the console is paused */
677 if (Console->UnpauseEvent != NULL) return STATUS_PENDING;
678
679 /* Convert the string to UNICODE */
680 if (Unicode)
681 {
682 Buffer = StringBuffer;
683 }
684 else
685 {
686 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
687 (PCHAR)StringBuffer,
688 NumCharsToWrite,
689 NULL, 0);
690 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
691 if (Buffer)
692 {
693 MultiByteToWideChar(Console->OutputCodePage, 0,
694 (PCHAR)StringBuffer,
695 NumCharsToWrite,
696 (PWCHAR)Buffer, Length);
697 }
698 else
699 {
700 Status = STATUS_NO_MEMORY;
701 }
702 }
703
704 /* Send it */
705 if (Buffer)
706 {
707 if (NT_SUCCESS(Status))
708 {
709 Status = TermWriteStream(Console,
710 ScreenBuffer,
711 Buffer,
712 NumCharsToWrite,
713 TRUE);
714 if (NT_SUCCESS(Status))
715 {
716 Written = NumCharsToWrite;
717 }
718 }
719
720 if (!Unicode) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
721 }
722
723 if (NumCharsWritten) *NumCharsWritten = Written;
724
725 return Status;
726 }
727
728 NTSTATUS FASTCALL
729 IntReadConsoleOutputStringAscii(IN PCONSOLE Console,
730 IN PTEXTMODE_SCREEN_BUFFER Buffer,
731 OUT PVOID StringBuffer,
732 IN ULONG NumCodesToRead,
733 IN PCOORD ReadCoord,
734 OUT PULONG NumCodesRead OPTIONAL)
735 {
736 ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
737 LPBYTE ReadBuffer = StringBuffer;
738 SHORT Xpos = ReadCoord->X;
739 SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
740 ULONG i;
741 PCHAR_INFO Ptr;
742 BOOLEAN bCJK = Console->IsCJK;
743
744 for (i = 0; i < NumCodesToRead; ++i)
745 {
746 Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
747
748 ConsoleOutputUnicodeToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
749 ReadBuffer += CodeSize;
750
751 Xpos++;
752 if (Xpos == Buffer->ScreenBufferSize.X)
753 {
754 Xpos = 0;
755 Ypos++;
756 if (Ypos == Buffer->ScreenBufferSize.Y)
757 {
758 Ypos = 0;
759 }
760 }
761
762 /* For Chinese, Japanese and Korean */
763 if (bCJK && (Ptr->Attributes & COMMON_LVB_LEADING_BYTE))
764 {
765 Xpos++;
766 if (Xpos == Buffer->ScreenBufferSize.X)
767 {
768 Xpos = 0;
769 Ypos++;
770 if (Ypos == Buffer->ScreenBufferSize.Y)
771 {
772 Ypos = 0;
773 }
774 }
775 ++i;
776 }
777 }
778
779 if (NumCodesRead)
780 *NumCodesRead = i;
781
782 return STATUS_SUCCESS;
783 }
784
785 NTSTATUS FASTCALL
786 IntReadConsoleOutputStringUnicode(IN PCONSOLE Console,
787 IN PTEXTMODE_SCREEN_BUFFER Buffer,
788 OUT PVOID StringBuffer,
789 IN ULONG NumCodesToRead,
790 IN PCOORD ReadCoord,
791 OUT PULONG NumCodesRead OPTIONAL)
792 {
793 ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
794 LPBYTE ReadBuffer = StringBuffer;
795 SHORT Xpos = ReadCoord->X;
796 SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
797 ULONG i, nNumChars = 0;
798 PCHAR_INFO Ptr;
799 BOOLEAN bCJK = Console->IsCJK;
800
801 for (i = 0; i < NumCodesToRead; ++i, ++nNumChars)
802 {
803 Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
804
805 *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
806 ReadBuffer += CodeSize;
807
808 Xpos++;
809 if (Xpos == Buffer->ScreenBufferSize.X)
810 {
811 Xpos = 0;
812 Ypos++;
813 if (Ypos == Buffer->ScreenBufferSize.Y)
814 {
815 Ypos = 0;
816 }
817 }
818
819 /* For Chinese, Japanese and Korean */
820 if (bCJK && (Ptr->Attributes & COMMON_LVB_LEADING_BYTE))
821 {
822 Xpos++;
823 if (Xpos == Buffer->ScreenBufferSize.X)
824 {
825 Xpos = 0;
826 Ypos++;
827 if (Ypos == Buffer->ScreenBufferSize.Y)
828 {
829 Ypos = 0;
830 }
831 }
832 ++i;
833 }
834 }
835
836 if (NumCodesRead)
837 *NumCodesRead = nNumChars;
838
839 return STATUS_SUCCESS;
840 }
841
842 NTSTATUS FASTCALL
843 IntReadConsoleOutputStringAttributes(IN PCONSOLE Console,
844 IN PTEXTMODE_SCREEN_BUFFER Buffer,
845 OUT PVOID StringBuffer,
846 IN ULONG NumCodesToRead,
847 IN PCOORD ReadCoord,
848 OUT PULONG NumCodesRead OPTIONAL)
849 {
850 ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
851 LPBYTE ReadBuffer = StringBuffer;
852 SHORT Xpos = ReadCoord->X;
853 SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
854 ULONG i;
855 PCHAR_INFO Ptr;
856
857 for (i = 0; i < NumCodesToRead; ++i)
858 {
859 Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
860
861 *(PWORD)ReadBuffer = Ptr->Attributes;
862 ReadBuffer += CodeSize;
863
864 Xpos++;
865 if (Xpos == Buffer->ScreenBufferSize.X)
866 {
867 Xpos = 0;
868 Ypos++;
869 if (Ypos == Buffer->ScreenBufferSize.Y)
870 {
871 Ypos = 0;
872 }
873 }
874 }
875
876 if (Xpos > 0 && Console->IsCJK)
877 {
878 ReadBuffer -= CodeSize;
879 *(PWORD)ReadBuffer &= ~COMMON_LVB_LEADING_BYTE;
880 }
881
882 if (NumCodesRead)
883 *NumCodesRead = NumCodesToRead;
884
885 return STATUS_SUCCESS;
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 PULONG NumCodesRead OPTIONAL)
896 {
897 if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
898 {
899 return STATUS_INVALID_PARAMETER;
900 }
901
902 /* Validity checks */
903 ASSERT(Console == Buffer->Header.Console);
904 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToRead == 0));
905
906 if (NumCodesRead)
907 *NumCodesRead = 0;
908
909 switch (CodeType)
910 {
911 case CODE_ASCII:
912 return IntReadConsoleOutputStringAscii(Console,
913 Buffer,
914 StringBuffer,
915 NumCodesToRead,
916 ReadCoord,
917 NumCodesRead);
918
919 case CODE_UNICODE:
920 return IntReadConsoleOutputStringUnicode(Console,
921 Buffer,
922 StringBuffer,
923 NumCodesToRead,
924 ReadCoord,
925 NumCodesRead);
926
927 case CODE_ATTRIBUTE:
928 return IntReadConsoleOutputStringAttributes(Console,
929 Buffer,
930 StringBuffer,
931 NumCodesToRead,
932 ReadCoord,
933 NumCodesRead);
934
935 default:
936 return STATUS_INVALID_PARAMETER;
937 }
938 }
939
940 static NTSTATUS
941 IntWriteConsoleOutputStringUnicode(
942 IN PCONSOLE Console,
943 IN PTEXTMODE_SCREEN_BUFFER Buffer,
944 IN PVOID StringBuffer,
945 IN ULONG NumCodesToWrite,
946 IN PCOORD WriteCoord,
947 OUT PULONG NumCodesWritten OPTIONAL)
948 {
949 NTSTATUS Status = STATUS_SUCCESS;
950 PWCHAR WriteBuffer = StringBuffer;
951 ULONG i, X, Y, Length;
952 PCHAR_INFO Ptr;
953 BOOLEAN bCJK = Console->IsCJK;
954
955 if (!StringBuffer)
956 goto Cleanup;
957
958 X = WriteCoord->X;
959 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
960 Length = NumCodesToWrite;
961
962 for (i = 0; i < Length; ++i)
963 {
964 Ptr = ConioCoordToPointer(Buffer, X, Y);
965
966 Ptr->Char.UnicodeChar = *WriteBuffer;
967 ++WriteBuffer;
968
969 ++X;
970 if (X == Buffer->ScreenBufferSize.X)
971 {
972 X = 0;
973 ++Y;
974 if (Y == Buffer->ScreenBufferSize.Y)
975 {
976 Y = 0;
977 }
978 }
979
980 /* For Chinese, Japanese and Korean */
981 if (bCJK && Ptr->Char.UnicodeChar >= 0x80 &&
982 mk_wcwidth_cjk(Ptr->Char.UnicodeChar) == 2)
983 {
984 /* A full-width character cannot cross a line boundary */
985 if (X == Buffer->ScreenBufferSize.X - 1)
986 {
987 /* go to next line */
988 X = 0;
989 ++Y;
990 if (Y == Buffer->ScreenBufferSize.Y)
991 {
992 Y = 0;
993 }
994 Ptr = ConioCoordToPointer(Buffer, X, Y);
995 }
996
997 /* the leading byte */
998 Ptr->Attributes = Buffer->ScreenDefaultAttrib;
999 Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
1000 ++i;
1001
1002 /* the trailing byte */
1003 Ptr = ConioCoordToPointer(Buffer, X, Y);
1004 Ptr->Attributes = Buffer->ScreenDefaultAttrib;
1005 Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
1006
1007 ++X;
1008 if (X == Buffer->ScreenBufferSize.X)
1009 {
1010 X = 0;
1011 ++Y;
1012 if (Y == Buffer->ScreenBufferSize.Y)
1013 {
1014 Y = 0;
1015 }
1016 }
1017 }
1018 }
1019
1020 Cleanup:
1021 if (NumCodesWritten)
1022 *NumCodesWritten = NumCodesToWrite;
1023 return Status;
1024 }
1025
1026 static NTSTATUS
1027 IntWriteConsoleOutputStringAscii(
1028 IN PCONSOLE Console,
1029 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1030 IN PVOID StringBuffer,
1031 IN ULONG NumCodesToWrite,
1032 IN PCOORD WriteCoord,
1033 OUT PULONG NumCodesWritten OPTIONAL)
1034 {
1035 NTSTATUS Status;
1036 PWCHAR tmpString;
1037 ULONG Length;
1038
1039 if (!StringBuffer)
1040 {
1041 if (NumCodesWritten)
1042 *NumCodesWritten = NumCodesToWrite;
1043
1044 return STATUS_SUCCESS;
1045 }
1046
1047 /* Convert the ASCII string into Unicode before writing it to the console */
1048 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
1049 StringBuffer,
1050 NumCodesToWrite,
1051 NULL, 0);
1052 tmpString = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
1053 if (!tmpString)
1054 return STATUS_NO_MEMORY;
1055
1056 MultiByteToWideChar(Console->OutputCodePage, 0,
1057 StringBuffer,
1058 NumCodesToWrite,
1059 tmpString, Length);
1060
1061 Status = IntWriteConsoleOutputStringUnicode(Console,
1062 Buffer,
1063 tmpString,
1064 Length,
1065 WriteCoord,
1066 NumCodesWritten);
1067 ConsoleFreeHeap(tmpString);
1068 return Status;
1069 }
1070
1071 static NTSTATUS
1072 IntWriteConsoleOutputStringAttribute(
1073 IN PCONSOLE Console,
1074 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1075 IN PVOID StringBuffer,
1076 IN ULONG NumCodesToWrite,
1077 IN PCOORD WriteCoord,
1078 OUT PULONG NumCodesWritten OPTIONAL)
1079 {
1080 NTSTATUS Status = STATUS_SUCCESS;
1081 PWORD WriteBuffer = StringBuffer;
1082 ULONG i, X, Y, Length;
1083 PCHAR_INFO Ptr;
1084
1085 if (!StringBuffer)
1086 goto Cleanup;
1087
1088 X = WriteCoord->X;
1089 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1090 Length = NumCodesToWrite;
1091
1092 for (i = 0; i < Length; ++i)
1093 {
1094 Ptr = ConioCoordToPointer(Buffer, X, Y);
1095
1096 Ptr->Attributes = (*WriteBuffer & ~COMMON_LEAD_TRAIL);
1097 ++WriteBuffer;
1098
1099 ++X;
1100 if (X == Buffer->ScreenBufferSize.X)
1101 {
1102 X = 0;
1103 ++Y;
1104 if (Y == Buffer->ScreenBufferSize.Y)
1105 {
1106 Y = 0;
1107 }
1108 }
1109 }
1110
1111 Cleanup:
1112 if (NumCodesWritten)
1113 *NumCodesWritten = NumCodesToWrite;
1114 return Status;
1115 }
1116
1117 NTSTATUS NTAPI
1118 ConDrvWriteConsoleOutputString(
1119 IN PCONSOLE Console,
1120 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1121 IN CODE_TYPE CodeType,
1122 IN PVOID StringBuffer,
1123 IN ULONG NumCodesToWrite,
1124 IN PCOORD WriteCoord,
1125 OUT PULONG NumCodesWritten OPTIONAL)
1126 {
1127 NTSTATUS Status;
1128 SMALL_RECT UpdateRect;
1129
1130 if (Console == NULL || Buffer == NULL || WriteCoord == NULL /* || EndCoord == NULL */)
1131 {
1132 return STATUS_INVALID_PARAMETER;
1133 }
1134
1135 /* Validity checks */
1136 ASSERT(Console == Buffer->Header.Console);
1137 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToWrite == 0));
1138
1139 if (NumCodesWritten)
1140 *NumCodesWritten = 0;
1141
1142 switch (CodeType)
1143 {
1144 case CODE_ASCII:
1145 Status = IntWriteConsoleOutputStringAscii(
1146 Console, Buffer, StringBuffer, NumCodesToWrite, WriteCoord, NumCodesWritten);
1147 break;
1148
1149 case CODE_UNICODE:
1150 Status = IntWriteConsoleOutputStringUnicode(
1151 Console, Buffer, StringBuffer, NumCodesToWrite, WriteCoord, NumCodesWritten);
1152 break;
1153
1154 case CODE_ATTRIBUTE:
1155 Status = IntWriteConsoleOutputStringAttribute(
1156 Console, Buffer, StringBuffer, NumCodesToWrite, WriteCoord, NumCodesWritten);
1157 break;
1158
1159 default:
1160 Status = STATUS_INVALID_PARAMETER;
1161 break;
1162 }
1163
1164 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1165 {
1166 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1167 TermDrawRegion(Console, &UpdateRect);
1168 }
1169
1170 return Status;
1171 }
1172
1173 NTSTATUS NTAPI
1174 ConDrvFillConsoleOutput(IN PCONSOLE Console,
1175 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1176 IN CODE_TYPE CodeType,
1177 IN CODE_ELEMENT Code,
1178 IN ULONG NumCodesToWrite,
1179 IN PCOORD WriteCoord,
1180 OUT PULONG NumCodesWritten OPTIONAL)
1181 {
1182 ULONG X, Y, i;
1183 PCHAR_INFO Ptr;
1184 BOOLEAN bLead, bFullwidth;
1185
1186 if (Console == NULL || Buffer == NULL || WriteCoord == NULL)
1187 {
1188 return STATUS_INVALID_PARAMETER;
1189 }
1190
1191 /* Validity check */
1192 ASSERT(Console == Buffer->Header.Console);
1193
1194 //
1195 // FIXME: Make overflow checks on WriteCoord !!!!!!
1196 //
1197
1198 if (NumCodesWritten) *NumCodesWritten = 0;
1199
1200 if (CodeType == CODE_ASCII)
1201 {
1202 /* Conversion from the ASCII char to the UNICODE char */
1203 CODE_ELEMENT tmp;
1204 ConsoleOutputAnsiToUnicodeChar(Console, &tmp.UnicodeChar, &Code.AsciiChar);
1205 Code = tmp;
1206 }
1207
1208 X = WriteCoord->X;
1209 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1210 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1211 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1212
1213 /* For Chinese, Japanese and Korean */
1214 bLead = TRUE;
1215 bFullwidth = FALSE;
1216 if (Console->IsCJK)
1217 {
1218 bFullwidth = (mk_wcwidth_cjk(Code.UnicodeChar) == 2);
1219 if (X > 0)
1220 {
1221 Ptr = ConioCoordToPointer(Buffer, X - 1, Y);
1222 if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
1223 {
1224 Ptr->Char.UnicodeChar = L' ';
1225 Ptr->Attributes &= ~COMMON_LVB_LEADING_BYTE;
1226 }
1227 }
1228 }
1229
1230 for (i = 0; i < NumCodesToWrite; ++i)
1231 {
1232 Ptr = ConioCoordToPointer(Buffer, X, Y);
1233
1234 switch (CodeType)
1235 {
1236 case CODE_ASCII:
1237 case CODE_UNICODE:
1238 Ptr->Char.UnicodeChar = Code.UnicodeChar;
1239 Ptr->Attributes &= ~COMMON_LEAD_TRAIL;
1240 if (bFullwidth)
1241 {
1242 if (bLead)
1243 Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
1244 else
1245 Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
1246 }
1247 break;
1248
1249 case CODE_ATTRIBUTE:
1250 Ptr->Attributes &= ~COMMON_LEAD_TRAIL;
1251 Ptr->Attributes |= (Code.Attribute & ~COMMON_LEAD_TRAIL);
1252 break;
1253 }
1254
1255 ++X;
1256 if (X == Buffer->ScreenBufferSize.X)
1257 {
1258 X = 0;
1259 ++Y;
1260 if (Y == Buffer->ScreenBufferSize.Y)
1261 {
1262 Y = 0;
1263 }
1264 }
1265
1266 bLead = !bLead;
1267 }
1268
1269 if ((NumCodesToWrite & 1) & bFullwidth)
1270 {
1271 if (X + Y * Buffer->ScreenBufferSize.X > 0)
1272 {
1273 Ptr = ConioCoordToPointer(Buffer, X - 1, Y);
1274 Ptr->Char.UnicodeChar = L' ';
1275 Ptr->Attributes &= ~COMMON_LEAD_TRAIL;
1276 }
1277 }
1278
1279 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1280 {
1281 SMALL_RECT UpdateRect;
1282 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1283 TermDrawRegion(Console, &UpdateRect);
1284 }
1285
1286 if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
1287 return STATUS_SUCCESS;
1288 }
1289
1290 NTSTATUS NTAPI
1291 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console,
1292 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1293 OUT PCOORD ScreenBufferSize,
1294 OUT PCOORD CursorPosition,
1295 OUT PCOORD ViewOrigin,
1296 OUT PCOORD ViewSize,
1297 OUT PCOORD MaximumViewSize,
1298 OUT PWORD Attributes)
1299 {
1300 COORD LargestWindowSize;
1301
1302 if (Console == NULL || Buffer == NULL || ScreenBufferSize == NULL ||
1303 CursorPosition == NULL || ViewOrigin == NULL || ViewSize == NULL ||
1304 MaximumViewSize == NULL || Attributes == NULL)
1305 {
1306 return STATUS_INVALID_PARAMETER;
1307 }
1308
1309 /* Validity check */
1310 ASSERT(Console == Buffer->Header.Console);
1311
1312 *ScreenBufferSize = Buffer->ScreenBufferSize;
1313 *CursorPosition = Buffer->CursorPosition;
1314 *ViewOrigin = Buffer->ViewOrigin;
1315 *ViewSize = Buffer->ViewSize;
1316 *Attributes = Buffer->ScreenDefaultAttrib;
1317
1318 /*
1319 * Retrieve the largest possible console window size, taking
1320 * into account the size of the console screen buffer.
1321 */
1322 TermGetLargestConsoleWindowSize(Console, &LargestWindowSize);
1323 LargestWindowSize.X = min(LargestWindowSize.X, Buffer->ScreenBufferSize.X);
1324 LargestWindowSize.Y = min(LargestWindowSize.Y, Buffer->ScreenBufferSize.Y);
1325 *MaximumViewSize = LargestWindowSize;
1326
1327 return STATUS_SUCCESS;
1328 }
1329
1330 NTSTATUS NTAPI
1331 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
1332 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1333 IN WORD Attributes)
1334 {
1335 if (Console == NULL || Buffer == NULL)
1336 return STATUS_INVALID_PARAMETER;
1337
1338 /* Validity check */
1339 ASSERT(Console == Buffer->Header.Console);
1340
1341 Buffer->ScreenDefaultAttrib = Attributes;
1342 return STATUS_SUCCESS;
1343 }
1344
1345 NTSTATUS NTAPI
1346 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
1347 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1348 IN PCOORD Size)
1349 {
1350 NTSTATUS Status;
1351
1352 if (Console == NULL || Buffer == NULL || Size == NULL)
1353 return STATUS_INVALID_PARAMETER;
1354
1355 /* Validity check */
1356 ASSERT(Console == Buffer->Header.Console);
1357
1358 Status = ConioResizeBuffer(Console, Buffer, *Size);
1359 if (NT_SUCCESS(Status)) TermResizeTerminal(Console);
1360
1361 return Status;
1362 }
1363
1364 NTSTATUS NTAPI
1365 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
1366 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1367 IN BOOLEAN Unicode,
1368 IN PSMALL_RECT ScrollRectangle,
1369 IN BOOLEAN UseClipRectangle,
1370 IN PSMALL_RECT ClipRectangle OPTIONAL,
1371 IN PCOORD DestinationOrigin,
1372 IN CHAR_INFO FillChar)
1373 {
1374 COORD CapturedDestinationOrigin;
1375 SMALL_RECT ScreenBuffer;
1376 SMALL_RECT SrcRegion;
1377 SMALL_RECT DstRegion;
1378 SMALL_RECT UpdateRegion;
1379 SMALL_RECT CapturedClipRectangle;
1380
1381 if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
1382 (UseClipRectangle ? ClipRectangle == NULL : FALSE) || DestinationOrigin == NULL)
1383 {
1384 return STATUS_INVALID_PARAMETER;
1385 }
1386
1387 /* Validity check */
1388 ASSERT(Console == Buffer->Header.Console);
1389
1390 CapturedDestinationOrigin = *DestinationOrigin;
1391
1392 /* Make sure the source rectangle is inside the screen buffer */
1393 ConioInitRect(&ScreenBuffer, 0, 0,
1394 Buffer->ScreenBufferSize.Y - 1,
1395 Buffer->ScreenBufferSize.X - 1);
1396 if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, ScrollRectangle))
1397 {
1398 return STATUS_SUCCESS;
1399 }
1400
1401 /* If the source was clipped on the left or top, adjust the destination accordingly */
1402 if (ScrollRectangle->Left < 0)
1403 {
1404 CapturedDestinationOrigin.X -= ScrollRectangle->Left;
1405 }
1406 if (ScrollRectangle->Top < 0)
1407 {
1408 CapturedDestinationOrigin.Y -= ScrollRectangle->Top;
1409 }
1410
1411 if (UseClipRectangle)
1412 {
1413 CapturedClipRectangle = *ClipRectangle;
1414 if (!ConioGetIntersection(&CapturedClipRectangle, &CapturedClipRectangle, &ScreenBuffer))
1415 {
1416 return STATUS_SUCCESS;
1417 }
1418 }
1419 else
1420 {
1421 CapturedClipRectangle = ScreenBuffer;
1422 }
1423
1424 ConioInitRect(&DstRegion,
1425 CapturedDestinationOrigin.Y,
1426 CapturedDestinationOrigin.X,
1427 CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
1428 CapturedDestinationOrigin.X + ConioRectWidth(&SrcRegion ) - 1);
1429
1430 if (!Unicode)
1431 {
1432 WCHAR tmp;
1433 ConsoleOutputAnsiToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
1434 FillChar.Char.UnicodeChar = tmp;
1435 }
1436
1437 ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle, FillChar);
1438
1439 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1440 {
1441 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1442 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle))
1443 {
1444 /* Draw update region */
1445 TermDrawRegion(Console, &UpdateRegion);
1446 }
1447 }
1448
1449 return STATUS_SUCCESS;
1450 }
1451
1452 NTSTATUS NTAPI
1453 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
1454 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1455 IN BOOLEAN Absolute,
1456 IN PSMALL_RECT WindowRect)
1457 {
1458 SMALL_RECT CapturedWindowRect;
1459 COORD LargestWindowSize;
1460
1461 if (Console == NULL || Buffer == NULL || WindowRect == NULL)
1462 return STATUS_INVALID_PARAMETER;
1463
1464 /* Validity check */
1465 ASSERT(Console == Buffer->Header.Console);
1466
1467 CapturedWindowRect = *WindowRect;
1468
1469 if (!Absolute)
1470 {
1471 /* Relative positions are given, transform them to absolute ones */
1472 CapturedWindowRect.Left += Buffer->ViewOrigin.X;
1473 CapturedWindowRect.Top += Buffer->ViewOrigin.Y;
1474 CapturedWindowRect.Right += Buffer->ViewOrigin.X + Buffer->ViewSize.X - 1;
1475 CapturedWindowRect.Bottom += Buffer->ViewOrigin.Y + Buffer->ViewSize.Y - 1;
1476 }
1477
1478 /*
1479 * The MSDN documentation on SetConsoleWindowInfo is partially wrong about
1480 * the performed checks this API performs. While it is correct that the
1481 * 'Right'/'Bottom' members cannot be strictly smaller than the 'Left'/'Top'
1482 * members, they can be equal.
1483 * Also, if the 'Left' or 'Top' members are negative, this is automatically
1484 * corrected for, and the window rectangle coordinates are shifted accordingly.
1485 */
1486 if ((CapturedWindowRect.Right < CapturedWindowRect.Left) ||
1487 (CapturedWindowRect.Bottom < CapturedWindowRect.Top))
1488 {
1489 return STATUS_INVALID_PARAMETER;
1490 }
1491
1492 /*
1493 * Forbid window sizes larger than the largest allowed console window size,
1494 * taking into account the size of the console screen buffer.
1495 */
1496 TermGetLargestConsoleWindowSize(Console, &LargestWindowSize);
1497 LargestWindowSize.X = min(LargestWindowSize.X, Buffer->ScreenBufferSize.X);
1498 LargestWindowSize.Y = min(LargestWindowSize.Y, Buffer->ScreenBufferSize.Y);
1499 if ((CapturedWindowRect.Right - CapturedWindowRect.Left + 1 > LargestWindowSize.X) ||
1500 (CapturedWindowRect.Bottom - CapturedWindowRect.Top + 1 > LargestWindowSize.Y))
1501 {
1502 return STATUS_INVALID_PARAMETER;
1503 }
1504
1505 /* Shift the window rectangle coordinates if 'Left' or 'Top' are negative */
1506 if (CapturedWindowRect.Left < 0)
1507 {
1508 CapturedWindowRect.Right -= CapturedWindowRect.Left;
1509 CapturedWindowRect.Left = 0;
1510 }
1511 if (CapturedWindowRect.Top < 0)
1512 {
1513 CapturedWindowRect.Bottom -= CapturedWindowRect.Top;
1514 CapturedWindowRect.Top = 0;
1515 }
1516
1517 /* Clip the window rectangle to the screen buffer */
1518 CapturedWindowRect.Right = min(CapturedWindowRect.Right , Buffer->ScreenBufferSize.X);
1519 CapturedWindowRect.Bottom = min(CapturedWindowRect.Bottom, Buffer->ScreenBufferSize.Y);
1520
1521 Buffer->ViewOrigin.X = CapturedWindowRect.Left;
1522 Buffer->ViewOrigin.Y = CapturedWindowRect.Top;
1523
1524 Buffer->ViewSize.X = CapturedWindowRect.Right - CapturedWindowRect.Left + 1;
1525 Buffer->ViewSize.Y = CapturedWindowRect.Bottom - CapturedWindowRect.Top + 1;
1526
1527 TermResizeTerminal(Console);
1528
1529 return STATUS_SUCCESS;
1530 }
1531
1532 /* EOF */