|
3 | 3 | --********************************************************************/
|
4 | 4 |
|
5 | 5 | using System;
|
| 6 | +using System.ComponentModel; |
6 | 7 | using System.Diagnostics.CodeAnalysis;
|
7 | 8 | using System.Globalization;
|
8 | 9 | using System.Runtime.InteropServices;
|
9 | 10 | using System.Text;
|
| 11 | +using Microsoft.PowerShell.Internal; |
| 12 | +using Microsoft.Win32.SafeHandles; |
10 | 13 |
|
11 | 14 | namespace Microsoft.PowerShell
|
12 | 15 | {
|
@@ -403,4 +406,206 @@ public static string ToGestureString(this ConsoleKeyInfo key)
|
403 | 406 | return sb.ToString();
|
404 | 407 | }
|
405 | 408 | }
|
| 409 | + |
| 410 | + internal class ConhostConsole : IConsole |
| 411 | + { |
| 412 | + private readonly Lazy<SafeFileHandle> _inputHandle = new Lazy<SafeFileHandle>(() => |
| 413 | + { |
| 414 | + // We use CreateFile here instead of GetStdWin32Handle, as GetStdWin32Handle will return redirected handles |
| 415 | + var handle = NativeMethods.CreateFile( |
| 416 | + "CONIN$", |
| 417 | + (UInt32)(AccessQualifiers.GenericRead | AccessQualifiers.GenericWrite), |
| 418 | + (UInt32)ShareModes.ShareWrite, |
| 419 | + (IntPtr)0, |
| 420 | + (UInt32)CreationDisposition.OpenExisting, |
| 421 | + 0, |
| 422 | + (IntPtr)0); |
| 423 | + |
| 424 | + if (handle == NativeMethods.INVALID_HANDLE_VALUE) |
| 425 | + { |
| 426 | + int err = Marshal.GetLastWin32Error(); |
| 427 | + Win32Exception innerException = new Win32Exception(err); |
| 428 | + throw new Exception("Failed to retreive the input console handle.", innerException); |
| 429 | + } |
| 430 | + |
| 431 | + return new SafeFileHandle(handle, true); |
| 432 | + }); |
| 433 | + |
| 434 | + public uint GetConsoleInputMode() |
| 435 | + { |
| 436 | + var handle = _inputHandle.Value.DangerousGetHandle(); |
| 437 | + uint result; |
| 438 | + NativeMethods.GetConsoleMode(handle, out result); |
| 439 | + return result; |
| 440 | + } |
| 441 | + |
| 442 | + public void SetConsoleInputMode(uint mode) |
| 443 | + { |
| 444 | + var handle = _inputHandle.Value.DangerousGetHandle(); |
| 445 | + NativeMethods.SetConsoleMode(handle, mode); |
| 446 | + } |
| 447 | + |
| 448 | + public ConsoleKeyInfo ReadKey() |
| 449 | + { |
| 450 | + return Console.ReadKey(true); |
| 451 | + } |
| 452 | + |
| 453 | + public bool KeyAvailable |
| 454 | + { |
| 455 | + get { return Console.KeyAvailable; } |
| 456 | + } |
| 457 | + |
| 458 | + public int CursorLeft |
| 459 | + { |
| 460 | + get { return Console.CursorLeft; } |
| 461 | + set { Console.CursorLeft = value; } |
| 462 | + } |
| 463 | + |
| 464 | + public int CursorTop |
| 465 | + { |
| 466 | + get { return Console.CursorTop; } |
| 467 | + set { Console.CursorTop = value; } |
| 468 | + } |
| 469 | + |
| 470 | + public int CursorSize |
| 471 | + { |
| 472 | + get { return Console.CursorSize; } |
| 473 | + set { Console.CursorSize = value; } |
| 474 | + } |
| 475 | + |
| 476 | + public int BufferWidth |
| 477 | + { |
| 478 | + get { return Console.BufferWidth; } |
| 479 | + set { Console.BufferWidth = value; } |
| 480 | + } |
| 481 | + |
| 482 | + public int BufferHeight |
| 483 | + { |
| 484 | + get { return Console.BufferHeight; } |
| 485 | + set { Console.BufferHeight = value; } |
| 486 | + } |
| 487 | + |
| 488 | + public int WindowWidth |
| 489 | + { |
| 490 | + get { return Console.WindowWidth; } |
| 491 | + set { Console.WindowWidth = value; } |
| 492 | + } |
| 493 | + |
| 494 | + public int WindowHeight |
| 495 | + { |
| 496 | + get { return Console.WindowHeight; } |
| 497 | + set { Console.WindowHeight = value; } |
| 498 | + } |
| 499 | + |
| 500 | + public int WindowTop |
| 501 | + { |
| 502 | + get { return Console.WindowTop; } |
| 503 | + set { Console.WindowTop = value; } |
| 504 | + } |
| 505 | + |
| 506 | + public ConsoleColor BackgroundColor |
| 507 | + { |
| 508 | + get { return Console.BackgroundColor; } |
| 509 | + set { Console.BackgroundColor = value; } |
| 510 | + } |
| 511 | + |
| 512 | + public ConsoleColor ForegroundColor |
| 513 | + { |
| 514 | + get { return Console.ForegroundColor; } |
| 515 | + set { Console.ForegroundColor = value; } |
| 516 | + } |
| 517 | + |
| 518 | + public void SetWindowPosition(int left, int top) |
| 519 | + { |
| 520 | + Console.SetWindowPosition(left, top); |
| 521 | + } |
| 522 | + |
| 523 | + public void SetCursorPosition(int left, int top) |
| 524 | + { |
| 525 | + Console.SetCursorPosition(left, top); |
| 526 | + } |
| 527 | + |
| 528 | + public void Write(string value) |
| 529 | + { |
| 530 | + Console.Write(value); |
| 531 | + } |
| 532 | + |
| 533 | + public void WriteLine(string value) |
| 534 | + { |
| 535 | + Console.WriteLine(value); |
| 536 | + } |
| 537 | + |
| 538 | + public void WriteBufferLines(CHAR_INFO[] buffer, ref int top) |
| 539 | + { |
| 540 | + var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output); |
| 541 | + |
| 542 | + int bufferWidth = Console.BufferWidth; |
| 543 | + int bufferLineCount = buffer.Length / bufferWidth; |
| 544 | + if ((top + bufferLineCount) > Console.BufferHeight) |
| 545 | + { |
| 546 | + var scrollCount = (top + bufferLineCount) - Console.BufferHeight; |
| 547 | + ScrollBuffer(scrollCount); |
| 548 | + top -= scrollCount; |
| 549 | + } |
| 550 | + var bufferSize = new COORD |
| 551 | + { |
| 552 | + X = (short) bufferWidth, |
| 553 | + Y = (short) bufferLineCount |
| 554 | + }; |
| 555 | + var bufferCoord = new COORD {X = 0, Y = 0}; |
| 556 | + var bottom = top + bufferLineCount - 1; |
| 557 | + var writeRegion = new SMALL_RECT |
| 558 | + { |
| 559 | + Top = (short) top, |
| 560 | + Left = 0, |
| 561 | + Bottom = (short) bottom, |
| 562 | + Right = (short) (bufferWidth - 1) |
| 563 | + }; |
| 564 | + NativeMethods.WriteConsoleOutput(handle, buffer, |
| 565 | + bufferSize, bufferCoord, ref writeRegion); |
| 566 | + |
| 567 | + // Now make sure the bottom line is visible |
| 568 | + if (bottom >= (Console.WindowTop + Console.WindowHeight)) |
| 569 | + { |
| 570 | + Console.CursorTop = bottom; |
| 571 | + } |
| 572 | + } |
| 573 | + |
| 574 | + public void ScrollBuffer(int lines) |
| 575 | + { |
| 576 | + var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output); |
| 577 | + |
| 578 | + var scrollRectangle = new SMALL_RECT |
| 579 | + { |
| 580 | + Top = (short) lines, |
| 581 | + Left = 0, |
| 582 | + Bottom = (short)(Console.BufferHeight - 1), |
| 583 | + Right = (short)Console.BufferWidth |
| 584 | + }; |
| 585 | + var destinationOrigin = new COORD {X = 0, Y = 0}; |
| 586 | + var fillChar = new CHAR_INFO(' ', Console.ForegroundColor, Console.BackgroundColor); |
| 587 | + NativeMethods.ScrollConsoleScreenBuffer(handle, ref scrollRectangle, IntPtr.Zero, destinationOrigin, ref fillChar); |
| 588 | + } |
| 589 | + |
| 590 | + public CHAR_INFO[] ReadBufferLines(int top, int count) |
| 591 | + { |
| 592 | + var result = new CHAR_INFO[BufferWidth * count]; |
| 593 | + var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output); |
| 594 | + |
| 595 | + var readBufferSize = new COORD { |
| 596 | + X = (short)BufferWidth, |
| 597 | + Y = (short)count}; |
| 598 | + var readBufferCoord = new COORD {X = 0, Y = 0}; |
| 599 | + var readRegion = new SMALL_RECT |
| 600 | + { |
| 601 | + Top = (short)top, |
| 602 | + Left = 0, |
| 603 | + Bottom = (short)(top + count), |
| 604 | + Right = (short)(BufferWidth - 1) |
| 605 | + }; |
| 606 | + NativeMethods.ReadConsoleOutput(handle, result, |
| 607 | + readBufferSize, readBufferCoord, ref readRegion); |
| 608 | + return result; |
| 609 | + } |
| 610 | + } |
406 | 611 | }
|
0 commit comments