diff --git a/CMakeLists.txt b/CMakeLists.txt
index 87f604844c32679924f19bb4fdde9ca90f55d28f..c4fe5e8811843db1f4333253dd8787171ae48cce 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -123,6 +123,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
   SET(KWSYS_USE_FStream 1)
   SET(KWSYS_USE_String 1)
   SET(KWSYS_USE_SystemInformation 1)
+  SET(KWSYS_USE_ConsoleBuf 1)
 ENDIF()
 
 # Enforce component dependencies.
@@ -154,6 +155,9 @@ ENDIF()
 IF(KWSYS_USE_FStream)
   SET(KWSYS_USE_Encoding 1)
 ENDIF()
+IF(KWSYS_USE_ConsoleBuf)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
 
 # Setup the large file support default.
 IF(KWSYS_LFS_DISABLE)
@@ -673,7 +677,7 @@ SET(KWSYS_HXX_FILES Configure String
 # Add selected C++ classes.
 SET(cppclasses
   Directory DynamicLoader Encoding Glob RegularExpression SystemTools
-  CommandLineArguments IOStream FStream SystemInformation
+  CommandLineArguments IOStream FStream SystemInformation ConsoleBuf
   )
 FOREACH(cpp ${cppclasses})
   IF(KWSYS_USE_${cpp})
@@ -926,6 +930,20 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
         testFStream
         )
     ENDIF()
+    IF(KWSYS_USE_ConsoleBuf)
+      ADD_EXECUTABLE(testConsoleBufChild testConsoleBufChild.cxx)
+      SET_PROPERTY(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE})
+      TARGET_LINK_LIBRARIES(testConsoleBufChild ${KWSYS_NAMESPACE})
+      SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
+        testConsoleBuf
+        )
+      IF("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" AND
+         NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0")
+        set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8)
+      ENDIF()
+      SET_PROPERTY(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS
+        KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
+    ENDIF()
     IF(KWSYS_USE_SystemInformation)
       SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation)
     ENDIF()
diff --git a/ConsoleBuf.hxx.in b/ConsoleBuf.hxx.in
new file mode 100644
index 0000000000000000000000000000000000000000..8aeeda17904421d99a14aa87ebf8444195e88b64
--- /dev/null
+++ b/ConsoleBuf.hxx.in
@@ -0,0 +1,348 @@
+/*============================================================================
+  KWSys - Kitware System Library
+  Copyright 2000-2016 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE@_ConsoleBuf_hxx
+#define @KWSYS_NAMESPACE@_ConsoleBuf_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+#include <@KWSYS_NAMESPACE@/Encoding.hxx>
+#include <string>
+#include <cstring>
+#include <sstream>
+#include <streambuf>
+#include <iostream>
+#include <stdexcept>
+
+#if defined(_WIN32)
+#  include <windows.h>
+#  if __cplusplus >= 201103L
+#    include <system_error>
+#  endif
+#endif
+
+namespace @KWSYS_NAMESPACE@
+{
+#if defined(_WIN32)
+
+  template<class CharT, class Traits = std::char_traits<CharT> >
+  class @KWSYS_NAMESPACE@_EXPORT BasicConsoleBuf :
+      public std::basic_streambuf<CharT, Traits> {
+    public:
+      typedef typename Traits::int_type int_type;
+      typedef typename Traits::char_type char_type;
+
+      class Manager {
+        public:
+          Manager(std::basic_ios<CharT, Traits> &ios, const bool err = false)
+            : m_consolebuf(0)
+          {
+            m_ios = &ios;
+            try {
+              m_consolebuf = new BasicConsoleBuf<CharT, Traits>(err);
+              m_streambuf = m_ios->rdbuf(m_consolebuf);
+            } catch (const std::runtime_error& ex) {
+              std::cerr << "Failed to create ConsoleBuf!" << std::endl
+                        << ex.what() << std::endl;
+            };
+          }
+
+          ~Manager()
+          {
+            if (m_consolebuf) {
+              delete m_consolebuf;
+              m_ios->rdbuf(m_streambuf);
+            }
+          }
+
+        private:
+          std::basic_ios<CharT, Traits> *m_ios;
+          std::basic_streambuf<CharT, Traits> *m_streambuf;
+          BasicConsoleBuf<CharT, Traits> *m_consolebuf;
+      };
+
+      BasicConsoleBuf(const bool err = false) :
+        flush_on_newline(true),
+        input_pipe_codepage(0),
+        output_pipe_codepage(0),
+        input_file_codepage(CP_UTF8),
+        output_file_codepage(CP_UTF8),
+        m_consolesCodepage(0)
+      {
+        m_hInput = ::GetStdHandle(STD_INPUT_HANDLE);
+        checkHandle(true, "STD_INPUT_HANDLE");
+        if (!setActiveInputCodepage()) {
+          throw std::runtime_error("setActiveInputCodepage failed!");
+        }
+        m_hOutput = err ? ::GetStdHandle(STD_ERROR_HANDLE) :
+                          ::GetStdHandle(STD_OUTPUT_HANDLE);
+        checkHandle(false, err ? "STD_ERROR_HANDLE" : "STD_OUTPUT_HANDLE");
+        if (!setActiveOutputCodepage()) {
+          throw std::runtime_error("setActiveOutputCodepage failed!");
+        }
+        _setg();
+        _setp();
+      }
+
+      ~BasicConsoleBuf() throw()
+      {
+        sync();
+      }
+
+      bool activateCodepageChange()
+      {
+        return setActiveInputCodepage() && setActiveOutputCodepage();
+      }
+
+    protected:
+      virtual int sync() {
+        bool success = true;
+        if (m_hInput && m_isConsoleInput &&
+            ::FlushConsoleInputBuffer(m_hInput) == 0) {
+          success = false;
+        }
+        if (m_hOutput && !m_obuffer.empty()) {
+          const std::wstring wbuffer = getBuffer(m_obuffer);
+          if (m_isConsoleOutput) {
+            DWORD charsWritten;
+            success = ::WriteConsoleW(m_hOutput, wbuffer.c_str(),
+                                      (DWORD)wbuffer.size(), &charsWritten,
+                                      NULL) == 0 ? false : true;
+          } else {
+            DWORD bytesWritten;
+            std::string buffer;
+            success = encodeOutputBuffer(wbuffer, buffer);
+            if (success) {
+              success = ::WriteFile(m_hOutput, buffer.c_str(),
+                                    (DWORD)buffer.size(), &bytesWritten,
+                                     NULL) == 0 ? false : true;
+            }
+          }
+        }
+        m_ibuffer.clear();
+        m_obuffer.clear();
+        _setg();
+        _setp();
+        return success ? 0 : -1;
+      }
+
+      virtual int_type underflow() {
+        if (this->gptr() >= this->egptr()) {
+          if (!m_hInput) {
+            _setg(true);
+            return Traits::eof();
+          }
+          if (m_isConsoleInput) {
+            wchar_t wbuffer[128];
+            DWORD charsRead;
+            if (::ReadConsoleW(m_hInput, wbuffer, (sizeof(wbuffer) / sizeof(wbuffer[0])) - 1,
+                               &charsRead, NULL) == 0 || charsRead == 0) {
+              _setg(true);
+              return Traits::eof();
+            }
+            wbuffer[charsRead] = L'\0';
+            setBuffer(wbuffer, m_ibuffer);
+          } else {
+            std::wstring totalBuffer;
+            std::wstring wbuffer;
+            char buffer[128];
+            DWORD bytesRead;
+            while (::ReadFile(m_hInput, buffer, (sizeof(buffer) / sizeof(buffer[0])) - 1,
+                              &bytesRead, NULL) == 0) {
+              if (::GetLastError() == ERROR_MORE_DATA) {
+                buffer[bytesRead] = '\0';
+                if (decodeInputBuffer(buffer, wbuffer)) {
+                  totalBuffer += wbuffer;
+                  continue;
+                }
+              }
+              _setg(true);
+              return Traits::eof();
+            }
+            buffer[bytesRead] = '\0';
+            if (!decodeInputBuffer(buffer, wbuffer)) {
+              _setg(true);
+              return Traits::eof();
+            }
+            totalBuffer += wbuffer;
+            setBuffer(totalBuffer, m_ibuffer);
+          }
+          _setg();
+        }
+        return Traits::to_int_type(*this->gptr());
+      }
+
+      virtual int_type overflow(int_type ch = Traits::eof()) {
+        if (!Traits::eq_int_type(ch, Traits::eof())) {
+          char_type chr = Traits::to_char_type(ch);
+          m_obuffer += chr;
+          if ((flush_on_newline && Traits::eq(chr, '\n')) ||
+              Traits::eq_int_type(ch, 0x00)) {
+            sync();
+          }
+          return ch;
+        }
+        sync();
+        return Traits::eof();
+      }
+
+    public:
+      bool flush_on_newline;
+      UINT input_pipe_codepage;
+      UINT output_pipe_codepage;
+      UINT input_file_codepage;
+      UINT output_file_codepage;
+
+    private:
+      HANDLE m_hInput;
+      HANDLE m_hOutput;
+      std::basic_string<char_type> m_ibuffer;
+      std::basic_string<char_type> m_obuffer;
+      bool m_isConsoleInput;
+      bool m_isConsoleOutput;
+      UINT m_activeInputCodepage;
+      UINT m_activeOutputCodepage;
+      UINT m_consolesCodepage;
+      void checkHandle(bool input, std::string handleName) {
+        if ((input && m_hInput == INVALID_HANDLE_VALUE) ||
+            (!input && m_hOutput == INVALID_HANDLE_VALUE)) {
+          std::string errmsg = "GetStdHandle(" + handleName +
+                               ") returned INVALID_HANDLE_VALUE";
+#if __cplusplus >= 201103L
+          throw std::system_error(::GetLastError(),
+                                  std::system_category(), errmsg);
+#else
+          throw std::runtime_error(errmsg);
+#endif
+        }
+      }
+      UINT getConsolesCodepage() {
+        if (!m_consolesCodepage) {
+          m_consolesCodepage = GetConsoleCP();
+          if (!m_consolesCodepage) {
+            m_consolesCodepage = GetACP();
+          }
+        }
+        return m_consolesCodepage;
+      }
+      bool setActiveInputCodepage() {
+        m_isConsoleInput = false;
+        switch (GetFileType(m_hInput)) {
+          case FILE_TYPE_DISK:
+            m_activeInputCodepage = input_file_codepage;
+            break;
+          case FILE_TYPE_CHAR:
+            m_isConsoleInput = true;
+            break;
+          case FILE_TYPE_PIPE:
+            m_activeInputCodepage = input_pipe_codepage;
+            break;
+          default:
+            return false;
+        }
+        if (!m_isConsoleInput && m_activeInputCodepage == 0) {
+          m_activeInputCodepage = getConsolesCodepage();
+        }
+        return true;
+      }
+      bool setActiveOutputCodepage() {
+        m_isConsoleOutput = false;
+        switch (GetFileType(m_hOutput)) {
+          case FILE_TYPE_DISK:
+            m_activeOutputCodepage = output_file_codepage;
+            break;
+          case FILE_TYPE_CHAR:
+            m_isConsoleOutput = true;
+            break;
+          case FILE_TYPE_PIPE:
+            m_activeOutputCodepage = output_pipe_codepage;
+            break;
+          default:
+            return false;
+        }
+        if (!m_isConsoleOutput && m_activeOutputCodepage == 0) {
+           m_activeOutputCodepage = getConsolesCodepage();
+        }
+        return true;
+      }
+      void _setg(bool empty = false) {
+        if (!empty) {
+          this->setg((char_type *)m_ibuffer.data(),
+                     (char_type *)m_ibuffer.data(),
+                     (char_type *)m_ibuffer.data() + m_ibuffer.size());
+        } else {
+          this->setg((char_type *)m_ibuffer.data(),
+                     (char_type *)m_ibuffer.data() + m_ibuffer.size(),
+                     (char_type *)m_ibuffer.data() + m_ibuffer.size());
+        }
+      }
+      void _setp() {
+        this->setp((char_type *)m_obuffer.data(),
+                   (char_type *)m_obuffer.data() + m_obuffer.size());
+      }
+      bool encodeOutputBuffer(const std::wstring wbuffer,
+                              std::string &buffer) {
+        const int length = WideCharToMultiByte(m_activeOutputCodepage, 0,
+                                               wbuffer.c_str(),
+                                               (int)wbuffer.size(), NULL, 0,
+                                               NULL, NULL);
+        char *buf = new char[length + 1];
+        const bool success = WideCharToMultiByte(m_activeOutputCodepage, 0,
+                                                 wbuffer.c_str(),
+                                                 (int)wbuffer.size(), buf,
+                                                 length, NULL, NULL) > 0
+                             ? true : false;
+        buf[length] = '\0';
+        buffer = buf;
+        delete[] buf;
+        return success;
+      }
+      bool decodeInputBuffer(const char *buffer, std::wstring &wbuffer) {
+        int actualCodepage = m_activeInputCodepage;
+        const char BOM_UTF8[] = { char(0xEF), char(0xBB), char(0xBF) };
+        if (std::memcmp(buffer, BOM_UTF8, sizeof(BOM_UTF8)) == 0) {
+          // PowerShell uses UTF-8 with BOM for pipes
+          actualCodepage = CP_UTF8;
+          buffer += sizeof(BOM_UTF8);
+        }
+        const int wlength = MultiByteToWideChar(actualCodepage, 0, buffer,
+                                                -1, NULL, 0);
+        wchar_t *wbuf = new wchar_t[wlength];
+        const bool success = MultiByteToWideChar(actualCodepage, 0, buffer,
+                                                 -1, wbuf, wlength) > 0
+                             ? true : false;
+        wbuffer = wbuf;
+        delete[] wbuf;
+        return success;
+      }
+      std::wstring getBuffer(const std::basic_string<char> buffer) {
+        return Encoding::ToWide(buffer);
+      }
+      std::wstring getBuffer(const std::basic_string<wchar_t> buffer) {
+        return buffer;
+      }
+      void setBuffer(const std::wstring wbuffer,
+                     std::basic_string<char> &target) {
+        target = Encoding::ToNarrow(wbuffer);
+      }
+      void setBuffer(const std::wstring wbuffer,
+                     std::basic_string<wchar_t> &target) {
+        target = wbuffer;
+      }
+
+  }; // BasicConsoleBuf class
+
+  typedef BasicConsoleBuf<char>    ConsoleBuf;
+  typedef BasicConsoleBuf<wchar_t> WConsoleBuf;
+
+#endif
+} // KWSYS_NAMESPACE
+
+#endif
diff --git a/testConsoleBuf.cxx b/testConsoleBuf.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..591a2d1709ee227a936a62e463b8a5b98c5e4c4f
--- /dev/null
+++ b/testConsoleBuf.cxx
@@ -0,0 +1,603 @@
+/*============================================================================
+  KWSys - Kitware System Library
+  Copyright 2000-2016 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+
+#include KWSYS_HEADER(Encoding.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+# include "Encoding.hxx.in"
+#endif
+
+#if defined(_WIN32)
+
+#include <windows.h>
+#include <string.h>
+#include <wchar.h>
+#include <iostream>
+#include <stdexcept>
+#include "testConsoleBuf.hxx"
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+# define KWSYS_WINDOWS_DEPRECATED_GetVersion
+#endif
+// يونيكود
+static const WCHAR UnicodeInputTestString[] = L"\u064A\u0648\u0646\u064A\u0643\u0648\u062F!";
+static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE;
+
+static const DWORD waitTimeout = 10 * 1000;
+static STARTUPINFO startupInfo;
+static PROCESS_INFORMATION processInfo;
+static HANDLE syncEvent;
+static std::string encodedInputTestString;
+static std::string encodedTestString;
+
+//----------------------------------------------------------------------------
+static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr)
+{
+  BOOL bInheritHandles = FALSE;
+  DWORD dwCreationFlags = 0;
+  memset(&processInfo, 0, sizeof(processInfo));
+  memset(&startupInfo, 0, sizeof(startupInfo));
+  startupInfo.cb = sizeof(startupInfo);
+  startupInfo.dwFlags = STARTF_USESHOWWINDOW;
+  startupInfo.wShowWindow = SW_HIDE;
+  if (hIn || hOut || hErr) {
+    startupInfo.dwFlags |= STARTF_USESTDHANDLES;
+    startupInfo.hStdInput = hIn;
+    startupInfo.hStdOutput = hOut;
+    startupInfo.hStdError = hErr;
+    bInheritHandles = TRUE;
+  }
+
+  WCHAR cmd[MAX_PATH];
+  if (GetModuleFileNameW(NULL, cmd, MAX_PATH) == 0) {
+    std::cerr << "GetModuleFileName failed!" << std::endl;
+    return false;
+  }
+  WCHAR *p = cmd + wcslen(cmd);
+  while (p > cmd && *p != L'\\') p--;
+  *(p+1) = 0;
+  wcscat(cmd, cmdConsoleBufChild);
+  wcscat(cmd, L".exe");
+
+  bool success = CreateProcessW(NULL,             // No module name (use command line)
+                                cmd,              // Command line
+                                NULL,             // Process handle not inheritable
+                                NULL,             // Thread handle not inheritable
+                                bInheritHandles,  // Set handle inheritance
+                                dwCreationFlags,
+                                NULL,             // Use parent's environment block
+                                NULL,             // Use parent's starting directory
+                                &startupInfo,     // Pointer to STARTUPINFO structure
+                                &processInfo) != 0; // Pointer to PROCESS_INFORMATION structure
+  if (!success) {
+    DWORD lastError = GetLastError();
+    std::cerr.setf(std::ios::hex, std::ios::basefield);
+    std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd)
+              << ") failed with error: 0x" << lastError << "!" << std::endl;
+    LPWSTR message;
+    if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                       NULL,
+                       lastError,
+                       0,
+                       (LPWSTR)&message, 0,
+                       NULL)
+    ) {
+      std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message) << std::endl;
+      HeapFree(GetProcessHeap(), 0, message);
+    } else {
+      std::cerr << "FormatMessage() failed with error: 0x" << GetLastError() << "!" << std::endl;
+    }
+    std::cerr.unsetf(std::ios::hex);
+  }
+  return success;
+}
+
+//----------------------------------------------------------------------------
+static void finishProcess(bool success)
+{
+  if (success) {
+    success = WaitForSingleObject(processInfo.hProcess, waitTimeout)
+              == WAIT_OBJECT_0;
+  };
+  if (!success) {
+    TerminateProcess(processInfo.hProcess, 1);
+  }
+  CloseHandle(processInfo.hProcess);
+  CloseHandle(processInfo.hThread);
+}
+
+//----------------------------------------------------------------------------
+static bool createPipe(PHANDLE readPipe, PHANDLE writePipe)
+{
+  SECURITY_ATTRIBUTES securityAttributes;
+  securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+  securityAttributes.bInheritHandle = TRUE;
+  securityAttributes.lpSecurityDescriptor = NULL;
+  return CreatePipe(readPipe, writePipe, &securityAttributes, 0) == 0
+         ? false : true;
+}
+
+//----------------------------------------------------------------------------
+static void finishPipe(HANDLE readPipe, HANDLE writePipe)
+{
+  if (readPipe != INVALID_HANDLE_VALUE) {
+    CloseHandle(readPipe);
+  }
+  if (writePipe != INVALID_HANDLE_VALUE) {
+    CloseHandle(writePipe);
+  }
+}
+
+//----------------------------------------------------------------------------
+static HANDLE createFile(LPCWSTR fileName)
+{
+  SECURITY_ATTRIBUTES securityAttributes;
+  securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+  securityAttributes.bInheritHandle = TRUE;
+  securityAttributes.lpSecurityDescriptor = NULL;
+
+  HANDLE file = CreateFileW(fileName,
+                            GENERIC_READ | GENERIC_WRITE,
+                            0,                    // do not share
+                            &securityAttributes,
+                            CREATE_ALWAYS,        // overwrite existing
+                            FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+                            NULL);                // no template
+  if (file == INVALID_HANDLE_VALUE) {
+    std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName)
+              << ") failed!" << std::endl;
+  }
+  return file;
+}
+
+//----------------------------------------------------------------------------
+static void finishFile(HANDLE file)
+{
+  if (file != INVALID_HANDLE_VALUE) {
+    CloseHandle(file);
+  }
+}
+
+//----------------------------------------------------------------------------
+
+#ifndef MAPVK_VK_TO_VSC
+#  define MAPVK_VK_TO_VSC  (0)
+#endif
+
+static void writeInputKeyEvent(INPUT_RECORD inputBuffer[], WCHAR chr)
+{
+  inputBuffer[0].EventType = KEY_EVENT;
+  inputBuffer[0].Event.KeyEvent.bKeyDown = TRUE;
+  inputBuffer[0].Event.KeyEvent.wRepeatCount = 1;
+  SHORT keyCode = VkKeyScanW(chr);
+  if (keyCode == -1) {
+    // Character can't be entered with current keyboard layout
+    // Just set any, it doesn't really matter
+    keyCode = 'K';
+  }
+  inputBuffer[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(keyCode);
+  inputBuffer[0].Event.KeyEvent.wVirtualScanCode =
+      MapVirtualKey(inputBuffer[0].Event.KeyEvent.wVirtualKeyCode,
+                    MAPVK_VK_TO_VSC);
+  inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar = chr;
+  inputBuffer[0].Event.KeyEvent.dwControlKeyState = 0;
+  if ((HIBYTE(keyCode) & 1) == 1) {
+    inputBuffer[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
+  }
+  if ((HIBYTE(keyCode) & 2) == 2) {
+    inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
+  }
+  if ((HIBYTE(keyCode) & 4) == 4) {
+    inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
+  }
+  inputBuffer[1].EventType = inputBuffer[0].EventType;
+  inputBuffer[1].Event.KeyEvent.bKeyDown = FALSE;
+  inputBuffer[1].Event.KeyEvent.wRepeatCount = 1;
+  inputBuffer[1].Event.KeyEvent.wVirtualKeyCode   = inputBuffer[0].Event.
+                                                      KeyEvent.wVirtualKeyCode;
+  inputBuffer[1].Event.KeyEvent.wVirtualScanCode  = inputBuffer[0].Event.
+                                                      KeyEvent.wVirtualScanCode;
+  inputBuffer[1].Event.KeyEvent.uChar.UnicodeChar = inputBuffer[0].Event.
+                                                      KeyEvent.uChar.UnicodeChar;
+  inputBuffer[1].Event.KeyEvent.dwControlKeyState = 0;
+}
+
+//----------------------------------------------------------------------------
+static int testPipe()
+{
+  int didFail = 1;
+  HANDLE inPipeRead = INVALID_HANDLE_VALUE;
+  HANDLE inPipeWrite = INVALID_HANDLE_VALUE;
+  HANDLE outPipeRead = INVALID_HANDLE_VALUE;
+  HANDLE outPipeWrite = INVALID_HANDLE_VALUE;
+  HANDLE errPipeRead = INVALID_HANDLE_VALUE;
+  HANDLE errPipeWrite = INVALID_HANDLE_VALUE;
+  UINT currentCodepage = GetConsoleCP();
+  char buffer[200];
+  try {
+    if (!createPipe(&inPipeRead, &inPipeWrite) ||
+        !createPipe(&outPipeRead, &outPipeWrite) ||
+        !createPipe(&errPipeRead, &errPipeWrite)) {
+      throw std::runtime_error("createFile failed!");
+    }
+    if (TestCodepage == CP_ACP) {
+      TestCodepage = GetACP();
+    }
+    if (!SetConsoleCP(TestCodepage)) {
+      throw std::runtime_error("SetConsoleCP failed!");
+    }
+
+    DWORD bytesWritten = 0;
+    if (!WriteFile(inPipeWrite, encodedInputTestString.c_str(),
+                   (DWORD)encodedInputTestString.size(), &bytesWritten, NULL)
+        || bytesWritten == 0) {
+      throw std::runtime_error("WriteFile failed!");
+    }
+
+    if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) {
+      try {
+        Sleep(100);
+        if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) {
+          throw std::runtime_error("WaitForSingleObject failed!");
+        }
+        DWORD bytesRead = 0;
+        if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead, NULL)
+            || bytesRead == 0) {
+          throw std::runtime_error("ReadFile failed!");
+        }
+        if ((bytesRead < encodedTestString.size() + 1 + encodedInputTestString.size()
+             && !ReadFile(outPipeRead, buffer + bytesRead,
+                          sizeof(buffer) - bytesRead, &bytesRead, NULL))
+            || bytesRead == 0) {
+          throw std::runtime_error("ReadFile failed!");
+        }
+        if (memcmp(buffer, encodedTestString.c_str(),
+                   encodedTestString.size()) == 0 &&
+            memcmp(buffer + encodedTestString.size() + 1,
+                   encodedInputTestString.c_str(),
+                   encodedInputTestString.size()) == 0) {
+          bytesRead = 0;
+          if (!ReadFile(errPipeRead, buffer, sizeof(buffer), &bytesRead, NULL)
+              || bytesRead == 0) {
+            throw std::runtime_error("ReadFile failed!");
+          }
+          buffer[bytesRead - 1] = 0;
+          didFail = encodedTestString.compare(buffer) == 0 ? 0 : 1;
+        }
+        if (didFail != 0) {
+          std::cerr << "Pipe's output didn't match expected output!" << std::endl << std::flush;
+        }
+      } catch (const std::runtime_error &ex) {
+        std::cerr << ex.what() << std::endl << std::flush;
+      }
+      finishProcess(didFail == 0);
+    }
+  } catch (const std::runtime_error &ex) {
+    std::cerr << ex.what() << std::endl << std::flush;
+  }
+  finishPipe(inPipeRead, inPipeWrite);
+  finishPipe(outPipeRead, outPipeWrite);
+  finishPipe(errPipeRead, errPipeWrite);
+  SetConsoleCP(currentCodepage);
+  return didFail;
+}
+
+//----------------------------------------------------------------------------
+static int testFile()
+{
+  int didFail = 1;
+  HANDLE inFile = INVALID_HANDLE_VALUE;
+  HANDLE outFile = INVALID_HANDLE_VALUE;
+  HANDLE errFile = INVALID_HANDLE_VALUE;
+  try {
+    if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE ||
+        (outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE ||
+        (errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) {
+      throw std::runtime_error("createFile failed!");
+    }
+    int length = 0;
+    DWORD bytesWritten = 0;
+    char buffer[200];
+
+    if ((length = WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, -1,
+                                      buffer, sizeof(buffer),
+                                      NULL, NULL)) == 0) {
+      throw std::runtime_error("WideCharToMultiByte failed!");
+    }
+    buffer[length - 1] = '\n';
+    if (!WriteFile(inFile, buffer, length, &bytesWritten, NULL)
+        || bytesWritten == 0) {
+      throw std::runtime_error("WriteFile failed!");
+    }
+    if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
+      throw std::runtime_error("SetFilePointer failed!");
+    }
+
+    if (createProcess(inFile, outFile, errFile)) {
+      DWORD bytesRead = 0;
+      try {
+        Sleep(100);
+        if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) {
+          throw std::runtime_error("WaitForSingleObject failed!");
+        }
+        if (SetFilePointer(outFile, 0, 0, FILE_BEGIN)
+            == INVALID_SET_FILE_POINTER) {
+          throw std::runtime_error("SetFilePointer failed!");
+        }
+        if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, NULL)
+            || bytesRead == 0) {
+          throw std::runtime_error("ReadFile failed!");
+        }
+        buffer[bytesRead - 1] = 0;
+        if (memcmp(buffer, encodedTestString.c_str(),
+                   encodedTestString.size()) == 0 &&
+            memcmp(buffer + encodedTestString.size() + 1,
+                   encodedInputTestString.c_str(),
+                   encodedInputTestString.size() - 1) == 0) {
+          bytesRead = 0;
+          if (SetFilePointer(errFile, 0, 0, FILE_BEGIN)
+              == INVALID_SET_FILE_POINTER) {
+            throw std::runtime_error("SetFilePointer failed!");
+          }
+          if (!ReadFile(errFile, buffer, sizeof(buffer), &bytesRead, NULL)
+              || bytesRead == 0) {
+            throw std::runtime_error("ReadFile failed!");
+          }
+          buffer[bytesRead - 1] = 0;
+          didFail = encodedTestString.compare(buffer) == 0 ? 0 : 1;
+        }
+        if (didFail != 0) {
+          std::cerr << "File's output didn't match expected output!" << std::endl << std::flush;
+        }
+      } catch (const std::runtime_error &ex) {
+        std::cerr << ex.what() << std::endl << std::flush;
+      }
+      finishProcess(didFail == 0);
+    }
+  } catch (const std::runtime_error &ex) {
+    std::cerr << ex.what() << std::endl << std::flush;
+  }
+  finishFile(inFile);
+  finishFile(outFile);
+  finishFile(errFile);
+  return didFail;
+}
+
+#ifndef _WIN32_WINNT_VISTA
+# define _WIN32_WINNT_VISTA 0x0600
+#endif
+
+//----------------------------------------------------------------------------
+static int testConsole()
+{
+  int didFail = 1;
+  HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE);
+  HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE);
+  HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE);
+  HANDLE hIn = parentIn;
+  HANDLE hOut = parentOut;
+  DWORD consoleMode;
+  bool newConsole = false;
+  bool forceNewConsole = false;
+  bool restoreConsole = false;
+  LPCWSTR TestFaceName = L"Lucida Console";
+  const DWORD TestFontFamily = 0x00000036;
+  const DWORD TestFontSize = 0x000c0000;
+  HKEY hConsoleKey;
+  WCHAR FaceName[200];
+  DWORD FaceNameSize = sizeof(FaceName);
+  DWORD FontFamily = TestFontFamily;
+  DWORD FontSize = TestFontSize;
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
+# pragma warning (push)
+# ifdef __INTEL_COMPILER
+#  pragma warning (disable:1478)
+# else
+#  pragma warning (disable:4996)
+# endif
+#endif
+  const bool isVistaOrGreater = LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA);
+#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
+# pragma warning (pop)
+#endif
+  if (!isVistaOrGreater) {
+    if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE,
+                      &hConsoleKey) == ERROR_SUCCESS) {
+      DWORD dwordSize = sizeof(DWORD);
+      if (RegQueryValueExW(hConsoleKey, L"FontFamily", NULL, NULL,
+                           (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) {
+        if (FontFamily != TestFontFamily) {
+          RegQueryValueExW(hConsoleKey, L"FaceName", NULL, NULL,
+                           (LPBYTE)FaceName, &FaceNameSize);
+          RegQueryValueExW(hConsoleKey, L"FontSize", NULL, NULL,
+                           (LPBYTE)&FontSize, &dwordSize);
+
+          RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
+                         (BYTE *)&TestFontFamily, sizeof(TestFontFamily));
+          RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ,
+                         (BYTE *)TestFaceName, (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR)));
+          RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD,
+                         (BYTE *)&TestFontSize, sizeof(TestFontSize));
+
+          restoreConsole = true;
+          forceNewConsole = true;
+        }
+      } else {
+        std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl << std::flush;
+      }
+      RegCloseKey(hConsoleKey);
+    } else {
+      std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!" << std::endl << std::flush;
+    }
+  }
+  if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) {
+    // Not a real console, let's create new one.
+    FreeConsole();
+    if (!AllocConsole()) {
+      std::cerr << "AllocConsole failed!" << std::endl << std::flush;
+      return didFail;
+    }
+    SECURITY_ATTRIBUTES securityAttributes;
+    securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+    securityAttributes.bInheritHandle = TRUE;
+    securityAttributes.lpSecurityDescriptor = NULL;
+    hIn  = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, 0,
+                       &securityAttributes, OPEN_EXISTING, 0, NULL);
+    hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, 0,
+                       &securityAttributes, OPEN_EXISTING, 0, NULL);
+    SetStdHandle(STD_INPUT_HANDLE, hIn);
+    SetStdHandle(STD_OUTPUT_HANDLE, hOut);
+    SetStdHandle(STD_ERROR_HANDLE, hOut);
+    newConsole = true;
+  }
+
+#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
+  if (isVistaOrGreater) {
+    CONSOLE_FONT_INFOEX consoleFont;
+    memset(&consoleFont, 0, sizeof(consoleFont));
+    consoleFont.cbSize = sizeof(consoleFont);
+    HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
+    typedef BOOL (WINAPI *GetCurrentConsoleFontExFunc)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
+    typedef BOOL (WINAPI *SetCurrentConsoleFontExFunc)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
+    GetCurrentConsoleFontExFunc getConsoleFont = (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32, "GetCurrentConsoleFontEx");
+    SetCurrentConsoleFontExFunc setConsoleFont = (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32, "SetCurrentConsoleFontEx");
+    if (getConsoleFont(hOut, FALSE, &consoleFont)) {
+      if (consoleFont.FontFamily != TestFontFamily) {
+        consoleFont.FontFamily = TestFontFamily;
+        wcscpy(consoleFont.FaceName, TestFaceName);
+        if (!setConsoleFont(hOut, FALSE, &consoleFont)) {
+          std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl << std::flush;
+        }
+      }
+    } else {
+      std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl << std::flush;
+    }
+  } else {
+#endif
+    if (restoreConsole && RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0,
+                                        KEY_WRITE, &hConsoleKey) == ERROR_SUCCESS) {
+      RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD,
+                     (BYTE *)&FontFamily, sizeof(FontFamily));
+      RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ,
+                     (BYTE *)FaceName, FaceNameSize);
+      RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD,
+                     (BYTE *)&FontSize, sizeof(FontSize));
+      RegCloseKey(hConsoleKey);
+    }
+#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
+  }
+#endif
+
+  if (createProcess(NULL, NULL, NULL)) {
+    try {
+      if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) {
+        throw std::runtime_error("WaitForSingleObject failed!");
+      }
+      INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) /
+                                sizeof(UnicodeInputTestString[0])) * 2];
+      memset(&inputBuffer, 0, sizeof(inputBuffer));
+      unsigned int i = 0;
+      for (i = 0; i < (sizeof(UnicodeInputTestString) /
+                       sizeof(UnicodeInputTestString[0]) - 1); i++) {
+        writeInputKeyEvent(&inputBuffer[i*2], UnicodeInputTestString[i]);
+      }
+      writeInputKeyEvent(&inputBuffer[i*2], VK_RETURN);
+      DWORD eventsWritten = 0;
+      if (!WriteConsoleInputW(hIn, inputBuffer, sizeof(inputBuffer) /
+                                                sizeof(inputBuffer[0]),
+                              &eventsWritten) || eventsWritten == 0) {
+        throw std::runtime_error("WriteConsoleInput failed!");
+      }
+      if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) {
+        throw std::runtime_error("WaitForSingleObject failed!");
+      }
+      CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
+      if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) {
+        throw std::runtime_error("GetConsoleScreenBufferInfo failed!");
+      }
+
+      COORD coord;
+      DWORD charsRead = 0;
+      coord.X = 0;
+      coord.Y = screenBufferInfo.dwCursorPosition.Y - 4;
+      WCHAR *outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4];
+      if (!ReadConsoleOutputCharacterW(hOut, outputBuffer,
+          screenBufferInfo.dwSize.X * 4, coord, &charsRead)
+          || charsRead == 0) {
+        delete[] outputBuffer;
+        throw std::runtime_error("ReadConsoleOutputCharacter failed!");
+      }
+      std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString);
+      std::wstring wideInputTestString = kwsys::Encoding::ToWide(encodedInputTestString);
+      if (memcmp(outputBuffer, wideTestString.c_str(), wideTestString.size()) == 0 &&
+          memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1,
+                 wideTestString.c_str(), wideTestString.size()) == 0 &&
+          memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2,
+                 UnicodeInputTestString, sizeof(UnicodeInputTestString) -
+                                         sizeof(WCHAR)) == 0 &&
+          memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3,
+                 wideInputTestString.c_str(), wideInputTestString.size() - 1) == 0
+      ) {
+        didFail = 0;
+      } else {
+        std::cerr << "Console's output didn't match expected output!" << std::endl << std::flush;
+      }
+      delete[] outputBuffer;
+    } catch (const std::runtime_error &ex) {
+      std::cerr << ex.what() << std::endl << std::flush;
+    }
+    finishProcess(didFail == 0);
+  }
+  if (newConsole) {
+    SetStdHandle(STD_INPUT_HANDLE, parentIn);
+    SetStdHandle(STD_OUTPUT_HANDLE, parentOut);
+    SetStdHandle(STD_ERROR_HANDLE, parentErr);
+    CloseHandle(hIn);
+    CloseHandle(hOut);
+    FreeConsole();
+  }
+  return didFail;
+}
+
+#endif
+
+//----------------------------------------------------------------------------
+int testConsoleBuf(int, char*[])
+{
+  int ret = 0;
+
+#if defined(_WIN32)
+  syncEvent = CreateEventW(NULL,
+                           FALSE,  // auto-reset event
+                           FALSE,  // initial state is nonsignaled
+                           SyncEventName);  // object name
+  if (!syncEvent) {
+    std::cerr << "CreateEvent failed " << GetLastError() << std::endl;
+    return 1;
+  }
+
+  encodedTestString = kwsys::Encoding::ToNarrow(UnicodeTestString);
+  encodedInputTestString = kwsys::Encoding::ToNarrow(UnicodeInputTestString);
+  encodedInputTestString += "\n";
+
+  ret |= testPipe();
+  ret |= testFile();
+  ret |= testConsole();
+
+  CloseHandle(syncEvent);
+#endif
+
+  return ret;
+}
diff --git a/testConsoleBuf.hxx b/testConsoleBuf.hxx
new file mode 100644
index 0000000000000000000000000000000000000000..855028b3b28bce075212bde89788ebcb4d1adc55
--- /dev/null
+++ b/testConsoleBuf.hxx
@@ -0,0 +1,24 @@
+/*============================================================================
+  KWSys - Kitware System Library
+  Copyright 2000-2016 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef testConsoleBuf_hxx
+#define testConsoleBuf_hxx
+
+static const wchar_t cmdConsoleBufChild[] = L"testConsoleBufChild";
+
+static const wchar_t SyncEventName[] = L"SyncEvent";
+
+// यूनिकोड είναι здорово!
+static const wchar_t UnicodeTestString[] = L"\u092F\u0942\u0928\u093F\u0915\u094B\u0921 "
+                                           L"\u03B5\u03AF\u03BD\u03B1\u03B9 "
+                                           L"\u0437\u0434\u043E\u0440\u043E\u0432\u043E!";
+
+#endif
diff --git a/testConsoleBufChild.cxx b/testConsoleBufChild.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3b9ab71a5f9452fd9a70d75e2b00224bf1e348fe
--- /dev/null
+++ b/testConsoleBufChild.cxx
@@ -0,0 +1,61 @@
+/*============================================================================
+  KWSys - Kitware System Library
+  Copyright 2000-2016 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "kwsysPrivate.h"
+
+#include KWSYS_HEADER(ConsoleBuf.hxx)
+#include KWSYS_HEADER(Encoding.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+# include "ConsoleBuf.hxx.in"
+# include "Encoding.hxx.in"
+#endif
+
+#include <iostream>
+#include "testConsoleBuf.hxx"
+
+//----------------------------------------------------------------------------
+int main(int argc, const char* argv[])
+{
+#if defined(_WIN32)
+  kwsys::ConsoleBuf::Manager out(std::cout);
+  kwsys::ConsoleBuf::Manager err(std::cerr, true);
+  kwsys::ConsoleBuf::Manager in(std::cin);
+
+  if (argc > 1) {
+    std::cout << argv[1] << std::endl;
+    std::cerr << argv[1] << std::endl;
+  } else {
+    std::string str = kwsys::Encoding::ToNarrow(UnicodeTestString);
+    std::cout << str << std::endl;
+    std::cerr << str << std::endl;
+  }
+
+  std::string input;
+  HANDLE syncEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, SyncEventName);
+  if (syncEvent) {
+    SetEvent(syncEvent);
+  }
+
+  std::cin >> input;
+  std::cout << input << std::endl;
+  if (syncEvent) {
+    SetEvent(syncEvent);
+    CloseHandle(syncEvent);
+  }
+#else
+  static_cast<void>(argc);
+  static_cast<void>(argv);
+#endif
+  return 0;
+}