Terminal: Add required 3rdparty libraries

Change-Id: Ic477e305f78632f5c454cd639dfc7e41fb643fe1
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-02-23 12:45:15 +01:00
parent 61c09bcefb
commit 82194d7e9c
222 changed files with 33359 additions and 2 deletions

View File

@@ -721,3 +721,95 @@ SQLite (https://www.sqlite.org) is in the Public Domain.
public domain worldwide. This software is distributed without any warranty.
http://creativecommons.org/publicdomain/zero/1.0/
### WinPty
Implementation of a pseudo terminal for Windows.
https://github.com/rprichard/winpty
The MIT License (MIT)
Copyright (c) 2011-2016 Ryan Prichard
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
### ptyqt
Pty-Qt is small library for access to console applications by pseudo-terminal interface on Mac,
Linux and Windows. On Mac and Linux it uses standard PseudoTerminal API and on Windows it uses
WinPty(prefer) or ConPty.
https://github.com/kafeg/ptyqt
MIT License
Copyright (c) 2019 Vitaly Petrov, v31337@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
### libvterm
An abstract C99 library which implements a VT220 or xterm-like terminal emulator.
It doesn't use any particular graphics toolkit or output system, instead it invokes callback
function pointers that its embedding program should provide it to draw on its behalf.
It avoids calling malloc() during normal running state, allowing it to be used in embedded kernel
situations.
https://www.leonerd.org.uk/code/libvterm/
The MIT License
Copyright (c) 2008 Paul Evans <leonerd@leonerd.org.uk>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1002,5 +1002,49 @@
https://creativecommons.org/publicdomain/zero/1.0/
\li \b WinPty
Implementation of a pseudo terminal for Windows.
The sources can be found in:
\list
\li \l https://github.com/rprichard/winpty
\endlist
Distributed under the MIT license.
\include license-mit.qdocinc
\li \b ptyqt
Pty-Qt is small library for access to console applications by a
pseudo-terminal interface on \macos, Linux and Windows. On \macos and
Linux it uses standard PseudoTerminal API and on Windows it uses
WinPty or ConPty.
\list
\li \l https://github.com/kafeg/ptyqt
\endlist
Distributed under the MIT license.
\include license-mit.qdocinc
\li \b libvterm
An abstract C99 library, which implements a VT220 or xterm-like terminal
emulator. It doesn't use any particular graphics toolkit or output
system. Instead it invokes callback function pointers that its embedding
program should provide to draw on its behalf. It avoids calling malloc()
during normal running state, allowing it to be used in embedded kernels.
\list
\li \l https://www.leonerd.org.uk/code/libvterm/
\endlist
Distributed under the MIT license.
\include license-mit.qdocinc
\endlist
*/

View File

@@ -1,2 +1,8 @@
add_subdirectory(cplusplus)
add_subdirectory(syntax-highlighting)
add_subdirectory(libvterm)
add_subdirectory(libptyqt)
if(WIN32)
add_subdirectory(winpty)
endif()

View File

@@ -0,0 +1,28 @@
set(SOURCES
iptyprocess.h
ptyqt.cpp ptyqt.h
)
if (WIN32)
list(APPEND SOURCES
winptyprocess.cpp winptyprocess.h
conptyprocess.cpp conptyprocess.h
)
else()
list(APPEND SOURCES unixptyprocess.cpp unixptyprocess.h)
endif()
add_library(ptyqt STATIC ${SOURCES})
target_link_libraries(ptyqt PUBLIC Qt::Core)
if (WIN32)
target_link_libraries(ptyqt PRIVATE winpty Qt::Network)
#target_compile_definitions(ptyqt PRIVATE PTYQT_DEBUG)
endif()
set_target_properties(ptyqt
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}
QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON
POSITION_INDEPENDENT_CODE ON
)

21
src/libs/3rdparty/libptyqt/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Vitaly Petrov, v31337@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,346 @@
#include "conptyprocess.h"
#include <QFile>
#include <QFileInfo>
#include <QThread>
#include <sstream>
#include <QTimer>
#include <QMutexLocker>
#include <QCoreApplication>
#include <qt_windows.h>
#define READ_INTERVAL_MSEC 500
HRESULT ConPtyProcess::createPseudoConsoleAndPipes(HPCON* phPC, HANDLE* phPipeIn, HANDLE* phPipeOut, qint16 cols, qint16 rows)
{
HRESULT hr{ E_UNEXPECTED };
HANDLE hPipePTYIn{ INVALID_HANDLE_VALUE };
HANDLE hPipePTYOut{ INVALID_HANDLE_VALUE };
// Create the pipes to which the ConPTY will connect
if (CreatePipe(&hPipePTYIn, phPipeOut, NULL, 0) &&
CreatePipe(phPipeIn, &hPipePTYOut, NULL, 0))
{
// Create the Pseudo Console of the required size, attached to the PTY-end of the pipes
hr = m_winContext.createPseudoConsole({cols, rows}, hPipePTYIn, hPipePTYOut, 0, phPC);
// Note: We can close the handles to the PTY-end of the pipes here
// because the handles are dup'ed into the ConHost and will be released
// when the ConPTY is destroyed.
if (INVALID_HANDLE_VALUE != hPipePTYOut) CloseHandle(hPipePTYOut);
if (INVALID_HANDLE_VALUE != hPipePTYIn) CloseHandle(hPipePTYIn);
}
return hr;
}
// Initializes the specified startup info struct with the required properties and
// updates its thread attribute list with the specified ConPTY handle
HRESULT ConPtyProcess::initializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX* pStartupInfo, HPCON hPC)
{
HRESULT hr{ E_UNEXPECTED };
if (pStartupInfo)
{
SIZE_T attrListSize{};
pStartupInfo->StartupInfo.hStdInput = m_hPipeIn;
pStartupInfo->StartupInfo.hStdError = m_hPipeOut;
pStartupInfo->StartupInfo.hStdOutput = m_hPipeOut;
pStartupInfo->StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
pStartupInfo->StartupInfo.cb = sizeof(STARTUPINFOEX);
// Get the size of the thread attribute list.
InitializeProcThreadAttributeList(NULL, 1, 0, &attrListSize);
// Allocate a thread attribute list of the correct size
pStartupInfo->lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(
HeapAlloc(GetProcessHeap(), 0, attrListSize));
// Initialize thread attribute list
if (pStartupInfo->lpAttributeList
&& InitializeProcThreadAttributeList(pStartupInfo->lpAttributeList, 1, 0, &attrListSize))
{
// Set Pseudo Console attribute
hr = UpdateProcThreadAttribute(
pStartupInfo->lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
hPC,
sizeof(HPCON),
NULL,
NULL)
? S_OK
: HRESULT_FROM_WIN32(GetLastError());
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
return hr;
}
ConPtyProcess::ConPtyProcess()
: IPtyProcess()
, m_ptyHandler { INVALID_HANDLE_VALUE }
, m_hPipeIn { INVALID_HANDLE_VALUE }
, m_hPipeOut { INVALID_HANDLE_VALUE }
, m_readThread(nullptr)
{
}
ConPtyProcess::~ConPtyProcess()
{
kill();
}
bool ConPtyProcess::startProcess(const QString &executable,
const QStringList &arguments,
const QString &workingDir,
QStringList environment,
qint16 cols,
qint16 rows)
{
if (!isAvailable())
{
m_lastError = m_winContext.lastError();
return false;
}
//already running
if (m_ptyHandler != INVALID_HANDLE_VALUE)
return false;
QFileInfo fi(executable);
if (fi.isRelative() || !QFile::exists(executable)) {
//todo add auto-find executable in PATH env var
m_lastError = QString("ConPty Error: shell file path '%1' must be absolute").arg(executable);
return false;
}
m_shellPath = executable;
m_size = QPair<qint16, qint16>(cols, rows);
//env
std::wstringstream envBlock;
for (const QString &line: std::as_const(environment))
{
envBlock << line.toStdWString() << L'\0';
}
envBlock << L'\0';
std::wstring env = envBlock.str();
LPWSTR envArg = env.empty() ? nullptr : env.data();
QStringList exeAndArgs = arguments;
exeAndArgs.prepend(m_shellPath);
std::wstring cmdArg = exeAndArgs.join(" ").toStdWString();
HRESULT hr{ E_UNEXPECTED };
// Create the Pseudo Console and pipes to it
hr = createPseudoConsoleAndPipes(&m_ptyHandler, &m_hPipeIn, &m_hPipeOut, cols, rows);
if (S_OK != hr)
{
m_lastError = QString("ConPty Error: CreatePseudoConsoleAndPipes fail");
return false;
}
// Initialize the necessary startup info struct
if (S_OK != initializeStartupInfoAttachedToPseudoConsole(&m_shellStartupInfo, m_ptyHandler))
{
m_lastError = QString("ConPty Error: InitializeStartupInfoAttachedToPseudoConsole fail");
return false;
}
hr = CreateProcess(NULL, // No module name - use Command Line
cmdArg.data(), // Command Line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Inherit handles
EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // Creation flags
envArg, // Environment block
workingDir.toStdWString().c_str(), // Use parent's starting directory
&m_shellStartupInfo.StartupInfo, // Pointer to STARTUPINFO
&m_shellProcessInformation) // Pointer to PROCESS_INFORMATION
? S_OK
: GetLastError();
if (S_OK != hr)
{
m_lastError = QString("ConPty Error: Cannot create process -> %1").arg(hr);
return false;
}
m_pid = m_shellProcessInformation.dwProcessId;
// Notify when the shell process has been terminated
RegisterWaitForSingleObject(
&m_shellCloseWaitHandle,
m_shellProcessInformation.hProcess,
[](PVOID data, BOOLEAN) {
auto self = static_cast<ConPtyProcess *>(data);
DWORD exitCode = 0;
GetExitCodeProcess(self->m_shellProcessInformation.hProcess, &exitCode);
self->m_exitCode = exitCode;
// Do not respawn if the object is about to be destructed
if (!self->m_aboutToDestruct)
emit self->notifier()->aboutToClose();
},
this,
INFINITE,
WT_EXECUTEONLYONCE);
//this code runned in separate thread
m_readThread = QThread::create([this]()
{
//buffers
const DWORD BUFF_SIZE{ 1024 };
char szBuffer[BUFF_SIZE]{};
forever
{
DWORD dwBytesRead{};
// Read from the pipe
BOOL result = ReadFile(m_hPipeIn, szBuffer, BUFF_SIZE, &dwBytesRead, NULL);
const bool needMoreData = !result && GetLastError() == ERROR_MORE_DATA;
if (result || needMoreData) {
QMutexLocker locker(&m_bufferMutex);
m_buffer.m_readBuffer.append(szBuffer, dwBytesRead);
m_buffer.emitReadyRead();
}
const bool brokenPipe = !result && GetLastError() == ERROR_BROKEN_PIPE;
if (QThread::currentThread()->isInterruptionRequested() || brokenPipe)
break;
}
});
//start read thread
m_readThread->start();
return true;
}
bool ConPtyProcess::resize(qint16 cols, qint16 rows)
{
if (m_ptyHandler == nullptr)
{
return false;
}
bool res = SUCCEEDED(m_winContext.resizePseudoConsole(m_ptyHandler, {cols, rows}));
if (res)
{
m_size = QPair<qint16, qint16>(cols, rows);
}
return res;
return true;
}
bool ConPtyProcess::kill()
{
bool exitCode = false;
if (m_ptyHandler != INVALID_HANDLE_VALUE) {
m_aboutToDestruct = true;
// Close ConPTY - this will terminate client process if running
m_winContext.closePseudoConsole(m_ptyHandler);
// Clean-up the pipes
if (INVALID_HANDLE_VALUE != m_hPipeOut)
CloseHandle(m_hPipeOut);
if (INVALID_HANDLE_VALUE != m_hPipeIn)
CloseHandle(m_hPipeIn);
m_readThread->requestInterruption();
if (!m_readThread->wait(1000))
m_readThread->terminate();
m_readThread->deleteLater();
m_readThread = nullptr;
m_pid = 0;
m_ptyHandler = INVALID_HANDLE_VALUE;
m_hPipeIn = INVALID_HANDLE_VALUE;
m_hPipeOut = INVALID_HANDLE_VALUE;
CloseHandle(m_shellProcessInformation.hThread);
CloseHandle(m_shellProcessInformation.hProcess);
UnregisterWait(m_shellCloseWaitHandle);
// Cleanup attribute list
if (m_shellStartupInfo.lpAttributeList) {
DeleteProcThreadAttributeList(m_shellStartupInfo.lpAttributeList);
HeapFree(GetProcessHeap(), 0, m_shellStartupInfo.lpAttributeList);
}
exitCode = true;
}
return exitCode;
}
IPtyProcess::PtyType ConPtyProcess::type()
{
return PtyType::ConPty;
}
QString ConPtyProcess::dumpDebugInfo()
{
#ifdef PTYQT_DEBUG
return QString("PID: %1, Type: %2, Cols: %3, Rows: %4")
.arg(m_pid).arg(type())
.arg(m_size.first).arg(m_size.second);
#else
return QString("Nothing...");
#endif
}
QIODevice *ConPtyProcess::notifier()
{
return &m_buffer;
}
QByteArray ConPtyProcess::readAll()
{
QByteArray result;
{
QMutexLocker locker(&m_bufferMutex);
result.swap(m_buffer.m_readBuffer);
}
return result;
}
qint64 ConPtyProcess::write(const QByteArray &byteArray)
{
DWORD dwBytesWritten{};
WriteFile(m_hPipeOut, byteArray.data(), byteArray.size(), &dwBytesWritten, NULL);
return dwBytesWritten;
}
bool ConPtyProcess::isAvailable()
{
#ifdef TOO_OLD_WINSDK
return false; //very importnant! ConPty can be built, but it doesn't work if built with old sdk and Win10 < 1903
#endif
qint32 buildNumber = QSysInfo::kernelVersion().split(".").last().toInt();
if (buildNumber < CONPTY_MINIMAL_WINDOWS_VERSION)
return false;
return m_winContext.init();
}
void ConPtyProcess::moveToThread(QThread *targetThread)
{
//nothing for now...
}

View File

@@ -0,0 +1,167 @@
#ifndef CONPTYPROCESS_H
#define CONPTYPROCESS_H
#include "iptyprocess.h"
#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <QIODevice>
#include <QLibrary>
#include <QMutex>
#include <QTimer>
#include <QThread>
//Taken from the RS5 Windows SDK, but redefined here in case we're targeting <= 17733
//Just for compile, ConPty doesn't work with Windows SDK < 17733
#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
#define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE \
ProcThreadAttributeValue(22, FALSE, TRUE, FALSE)
typedef VOID* HPCON;
#define TOO_OLD_WINSDK
#endif
template <typename T>
std::vector<T> vectorFromString(const std::basic_string<T> &str)
{
return std::vector<T>(str.begin(), str.end());
}
//ConPTY available only on Windows 10 releazed after 1903 (19H1) Windows release
class WindowsContext
{
public:
typedef HRESULT (*CreatePseudoConsolePtr)(
COORD size, // ConPty Dimensions
HANDLE hInput, // ConPty Input
HANDLE hOutput, // ConPty Output
DWORD dwFlags, // ConPty Flags
HPCON* phPC); // ConPty Reference
typedef HRESULT (*ResizePseudoConsolePtr)(HPCON hPC, COORD size);
typedef VOID (*ClosePseudoConsolePtr)(HPCON hPC);
WindowsContext()
: createPseudoConsole(nullptr)
, resizePseudoConsole(nullptr)
, closePseudoConsole(nullptr)
{
}
bool init()
{
//already initialized
if (createPseudoConsole)
return true;
//try to load symbols from library
//if it fails -> we can't use ConPty API
HANDLE kernel32Handle = LoadLibraryExW(L"kernel32.dll", 0, 0);
if (kernel32Handle != nullptr)
{
createPseudoConsole = (CreatePseudoConsolePtr)GetProcAddress((HMODULE)kernel32Handle, "CreatePseudoConsole");
resizePseudoConsole = (ResizePseudoConsolePtr)GetProcAddress((HMODULE)kernel32Handle, "ResizePseudoConsole");
closePseudoConsole = (ClosePseudoConsolePtr)GetProcAddress((HMODULE)kernel32Handle, "ClosePseudoConsole");
if (createPseudoConsole == NULL || resizePseudoConsole == NULL || closePseudoConsole == NULL)
{
m_lastError = QString("WindowsContext/ConPty error: %1").arg("Invalid on load API functions");
return false;
}
}
else
{
m_lastError = QString("WindowsContext/ConPty error: %1").arg("Unable to load kernel32");
return false;
}
return true;
}
QString lastError()
{
return m_lastError;
}
public:
//vars
CreatePseudoConsolePtr createPseudoConsole;
ResizePseudoConsolePtr resizePseudoConsole;
ClosePseudoConsolePtr closePseudoConsole;
private:
QString m_lastError;
};
class PtyBuffer : public QIODevice
{
friend class ConPtyProcess;
Q_OBJECT
public:
//just empty realization, we need only 'readyRead' signal of this class
qint64 readData(char *data, qint64 maxlen) { return 0; }
qint64 writeData(const char *data, qint64 len) { return 0; }
bool isSequential() const { return true; }
qint64 bytesAvailable() const { return m_readBuffer.size(); }
qint64 size() const { return m_readBuffer.size(); }
void emitReadyRead()
{
//for emit signal from PtyBuffer own thread
QTimer::singleShot(1, this, [this]()
{
emit readyRead();
});
}
private:
QByteArray m_readBuffer;
};
class ConPtyProcess : public IPtyProcess
{
public:
ConPtyProcess();
~ConPtyProcess();
bool startProcess(const QString &executable,
const QStringList &arguments,
const QString &workingDir,
QStringList environment,
qint16 cols,
qint16 rows);
bool resize(qint16 cols, qint16 rows);
bool kill();
PtyType type();
QString dumpDebugInfo();
virtual QIODevice *notifier();
virtual QByteArray readAll();
virtual qint64 write(const QByteArray &byteArray);
bool isAvailable();
void moveToThread(QThread *targetThread);
private:
HRESULT createPseudoConsoleAndPipes(HPCON* phPC, HANDLE* phPipeIn, HANDLE* phPipeOut, qint16 cols, qint16 rows);
HRESULT initializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX* pStartupInfo, HPCON hPC);
private:
WindowsContext m_winContext;
HPCON m_ptyHandler;
HANDLE m_hPipeIn, m_hPipeOut;
QThread *m_readThread;
QMutex m_bufferMutex;
PtyBuffer m_buffer;
bool m_aboutToDestruct{false};
PROCESS_INFORMATION m_shellProcessInformation{};
HANDLE m_shellCloseWaitHandle{INVALID_HANDLE_VALUE};
STARTUPINFOEX m_shellStartupInfo{};
};
#endif // CONPTYPROCESS_H

View File

@@ -0,0 +1,56 @@
#ifndef IPTYPROCESS_H
#define IPTYPROCESS_H
#include <QDebug>
#include <QString>
#include <QThread>
#define CONPTY_MINIMAL_WINDOWS_VERSION 18309
class IPtyProcess
{
public:
enum PtyType { UnixPty = 0, WinPty = 1, ConPty = 2, AutoPty = 3 };
IPtyProcess() = default;
IPtyProcess(const IPtyProcess &) = delete;
IPtyProcess &operator=(const IPtyProcess &) = delete;
virtual ~IPtyProcess() {}
virtual bool startProcess(const QString &executable,
const QStringList &arguments,
const QString &workingDir,
QStringList environment,
qint16 cols,
qint16 rows)
= 0;
virtual bool resize(qint16 cols, qint16 rows) = 0;
virtual bool kill() = 0;
virtual PtyType type() = 0;
virtual QString dumpDebugInfo() = 0;
virtual QIODevice *notifier() = 0;
virtual QByteArray readAll() = 0;
virtual qint64 write(const QByteArray &byteArray) = 0;
virtual bool isAvailable() = 0;
virtual void moveToThread(QThread *targetThread) = 0;
qint64 pid() { return m_pid; }
QPair<qint16, qint16> size() { return m_size; }
const QString lastError() { return m_lastError; }
int exitCode() { return m_exitCode; }
bool toggleTrace()
{
m_trace = !m_trace;
return m_trace;
}
protected:
QString m_shellPath;
QString m_lastError;
qint64 m_pid{0};
int m_exitCode{0};
QPair<qint16, qint16> m_size; //cols / rows
bool m_trace{false};
};
#endif // IPTYPROCESS_H

45
src/libs/3rdparty/libptyqt/ptyqt.cpp vendored Normal file
View File

@@ -0,0 +1,45 @@
#include "ptyqt.h"
#include <utility>
#ifdef Q_OS_WIN
#include "winptyprocess.h"
#include "conptyprocess.h"
#endif
#ifdef Q_OS_UNIX
#include "unixptyprocess.h"
#endif
IPtyProcess *PtyQt::createPtyProcess(IPtyProcess::PtyType ptyType)
{
switch (ptyType)
{
#ifdef Q_OS_WIN
case IPtyProcess::PtyType::WinPty:
return new WinPtyProcess();
break;
case IPtyProcess::PtyType::ConPty:
return new ConPtyProcess();
break;
#endif
#ifdef Q_OS_UNIX
case IPtyProcess::PtyType::UnixPty:
return new UnixPtyProcess();
break;
#endif
case IPtyProcess::PtyType::AutoPty:
default:
break;
}
#ifdef Q_OS_WIN
if (ConPtyProcess().isAvailable())
return new ConPtyProcess();
else
return new WinPtyProcess();
#endif
#ifdef Q_OS_UNIX
return new UnixPtyProcess();
#endif
}

12
src/libs/3rdparty/libptyqt/ptyqt.h vendored Normal file
View File

@@ -0,0 +1,12 @@
#ifndef PTYQT_H
#define PTYQT_H
#include "iptyprocess.h"
class PtyQt
{
public:
static IPtyProcess *createPtyProcess(IPtyProcess::PtyType ptyType);
};
#endif // PTYQT_H

45
src/libs/3rdparty/libptyqt/ptyqt.qbs vendored Normal file
View File

@@ -0,0 +1,45 @@
import qbs
Project {
name: "ptyqt"
QtcLibrary {
Depends { name: "Qt.core" }
Depends { name: "Qt.network"; condition: qbs.targetOS.contains("windows") }
Depends { name: "winpty"; condition: qbs.targetOS.contains("windows") }
type: "staticlibrary"
files: [
"iptyprocess.h",
"ptyqt.cpp",
"ptyqt.h",
]
Group {
name: "ptyqt UNIX files"
condition: qbs.targetOS.contains("unix")
files: [
"unixptyprocess.cpp",
"unixptyprocess.h",
]
}
Group {
name: "ptyqt Windows files"
condition: qbs.targetOS.contains("windows")
files: [
"conptyprocess.cpp",
"conptyprocess.h",
"winptyprocess.cpp",
"winptyprocess.h",
]
}
Export {
Depends { name: "cpp" }
Depends { name: "winpty"; condition: qbs.targetOS.contains("windows") }
cpp.includePaths: base.concat(exportingProduct.sourceDirectory)
}
}
}

View File

@@ -0,0 +1,376 @@
#include "unixptyprocess.h"
#include <QStandardPaths>
#include <errno.h>
#include <termios.h>
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_FREEBSD)
#include <utmpx.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <QCoreApplication>
#include <QFileInfo>
UnixPtyProcess::UnixPtyProcess()
: IPtyProcess()
, m_readMasterNotify(0)
{
m_shellProcess.setWorkingDirectory(
QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
}
UnixPtyProcess::~UnixPtyProcess()
{
kill();
}
bool UnixPtyProcess::startProcess(const QString &shellPath,
const QStringList &arguments,
const QString &workingDir,
QStringList environment,
qint16 cols,
qint16 rows)
{
if (!isAvailable()) {
m_lastError = QString("UnixPty Error: unavailable");
return false;
}
if (m_shellProcess.state() == QProcess::Running)
return false;
QFileInfo fi(shellPath);
if (fi.isRelative() || !QFile::exists(shellPath)) {
//todo add auto-find executable in PATH env var
m_lastError = QString("UnixPty Error: shell file path must be absolute");
return false;
}
m_shellPath = shellPath;
m_size = QPair<qint16, qint16>(cols, rows);
int rc = 0;
m_shellProcess.m_handleMaster = ::posix_openpt(O_RDWR | O_NOCTTY);
if (m_shellProcess.m_handleMaster <= 0) {
m_lastError = QString("UnixPty Error: unable to open master -> %1").arg(QLatin1String(strerror(errno)));
kill();
return false;
}
m_shellProcess.m_handleSlaveName = QLatin1String(ptsname(m_shellProcess.m_handleMaster));
if (m_shellProcess.m_handleSlaveName.isEmpty()) {
m_lastError = QString("UnixPty Error: unable to get slave name -> %1").arg(QLatin1String(strerror(errno)));
kill();
return false;
}
rc = grantpt(m_shellProcess.m_handleMaster);
if (rc != 0) {
m_lastError
= QString("UnixPty Error: unable to change perms for slave -> %1").arg(QLatin1String(strerror(errno)));
kill();
return false;
}
rc = unlockpt(m_shellProcess.m_handleMaster);
if (rc != 0) {
m_lastError = QString("UnixPty Error: unable to unlock slave -> %1").arg(QLatin1String(strerror(errno)));
kill();
return false;
}
m_shellProcess.m_handleSlave = ::open(m_shellProcess.m_handleSlaveName.toLatin1().data(),
O_RDWR | O_NOCTTY);
if (m_shellProcess.m_handleSlave < 0) {
m_lastError = QString("UnixPty Error: unable to open slave -> %1").arg(QLatin1String(strerror(errno)));
kill();
return false;
}
rc = fcntl(m_shellProcess.m_handleMaster, F_SETFD, FD_CLOEXEC);
if (rc == -1) {
m_lastError
= QString("UnixPty Error: unable to set flags for master -> %1").arg(QLatin1String(strerror(errno)));
kill();
return false;
}
rc = fcntl(m_shellProcess.m_handleSlave, F_SETFD, FD_CLOEXEC);
if (rc == -1) {
m_lastError
= QString("UnixPty Error: unable to set flags for slave -> %1").arg(QLatin1String(strerror(errno)));
kill();
return false;
}
struct ::termios ttmode;
rc = tcgetattr(m_shellProcess.m_handleMaster, &ttmode);
if (rc != 0) {
m_lastError = QString("UnixPty Error: termios fail -> %1").arg(QLatin1String(strerror(errno)));
kill();
return false;
}
ttmode.c_iflag = ICRNL | IXON | IXANY | IMAXBEL | BRKINT;
#if defined(IUTF8)
ttmode.c_iflag |= IUTF8;
#endif
ttmode.c_oflag = OPOST | ONLCR;
ttmode.c_cflag = CREAD | CS8 | HUPCL;
ttmode.c_lflag = ICANON | ISIG | IEXTEN | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL;
ttmode.c_cc[VEOF] = 4;
ttmode.c_cc[VEOL] = -1;
ttmode.c_cc[VEOL2] = -1;
ttmode.c_cc[VERASE] = 0x7f;
ttmode.c_cc[VWERASE] = 23;
ttmode.c_cc[VKILL] = 21;
ttmode.c_cc[VREPRINT] = 18;
ttmode.c_cc[VINTR] = 3;
ttmode.c_cc[VQUIT] = 0x1c;
ttmode.c_cc[VSUSP] = 26;
ttmode.c_cc[VSTART] = 17;
ttmode.c_cc[VSTOP] = 19;
ttmode.c_cc[VLNEXT] = 22;
ttmode.c_cc[VDISCARD] = 15;
ttmode.c_cc[VMIN] = 1;
ttmode.c_cc[VTIME] = 0;
#if (__APPLE__)
ttmode.c_cc[VDSUSP] = 25;
ttmode.c_cc[VSTATUS] = 20;
#endif
cfsetispeed(&ttmode, B38400);
cfsetospeed(&ttmode, B38400);
rc = tcsetattr(m_shellProcess.m_handleMaster, TCSANOW, &ttmode);
if (rc != 0) {
m_lastError
= QString("UnixPty Error: unabble to set associated params -> %1").arg(QLatin1String(strerror(errno)));
kill();
return false;
}
m_readMasterNotify = new QSocketNotifier(m_shellProcess.m_handleMaster,
QSocketNotifier::Read,
&m_shellProcess);
m_readMasterNotify->setEnabled(true);
m_readMasterNotify->moveToThread(m_shellProcess.thread());
QObject::connect(m_readMasterNotify, &QSocketNotifier::activated, [this](int socket) {
Q_UNUSED(socket)
QByteArray buffer;
int size = 1025;
int readSize = 1024;
QByteArray data;
do {
char nativeBuffer[size];
int len = ::read(m_shellProcess.m_handleMaster, nativeBuffer, readSize);
data = QByteArray(nativeBuffer, len);
buffer.append(data);
} while (data.size() == readSize); //last data block always < readSize
m_shellReadBuffer.append(buffer);
m_shellProcess.emitReadyRead();
});
QObject::connect(&m_shellProcess, &QProcess::finished, &m_shellProcess, [this](int exitCode) {
m_exitCode = exitCode;
emit m_shellProcess.aboutToClose();
});
QStringList defaultVars;
defaultVars.append("TERM=xterm-256color");
defaultVars.append("ITERM_PROFILE=Default");
defaultVars.append("XPC_FLAGS=0x0");
defaultVars.append("XPC_SERVICE_NAME=0");
defaultVars.append("LANG=en_US.UTF-8");
defaultVars.append("LC_ALL=en_US.UTF-8");
defaultVars.append("LC_CTYPE=UTF-8");
defaultVars.append("INIT_CWD=" + QCoreApplication::applicationDirPath());
defaultVars.append("COMMAND_MODE=unix2003");
defaultVars.append("COLORTERM=truecolor");
QStringList varNames;
foreach (QString line, environment) {
varNames.append(line.split("=").first());
}
//append default env vars only if they don't exists in current env
foreach (QString defVar, defaultVars) {
if (!varNames.contains(defVar.split("=").first()))
environment.append(defVar);
}
QProcessEnvironment envFormat;
foreach (QString line, environment) {
envFormat.insert(line.split("=").first(), line.split("=").last());
}
m_shellProcess.setWorkingDirectory(workingDir);
m_shellProcess.setProcessEnvironment(envFormat);
m_shellProcess.setReadChannel(QProcess::StandardOutput);
m_shellProcess.start(m_shellPath, arguments);
m_shellProcess.waitForStarted();
m_pid = m_shellProcess.processId();
resize(cols, rows);
return true;
}
bool UnixPtyProcess::resize(qint16 cols, qint16 rows)
{
struct winsize winp;
winp.ws_col = cols;
winp.ws_row = rows;
winp.ws_xpixel = 0;
winp.ws_ypixel = 0;
bool res = ((ioctl(m_shellProcess.m_handleMaster, TIOCSWINSZ, &winp) != -1)
&& (ioctl(m_shellProcess.m_handleSlave, TIOCSWINSZ, &winp) != -1));
if (res) {
m_size = QPair<qint16, qint16>(cols, rows);
}
return res;
}
bool UnixPtyProcess::kill()
{
m_shellProcess.m_handleSlaveName = QString();
if (m_shellProcess.m_handleSlave >= 0) {
::close(m_shellProcess.m_handleSlave);
m_shellProcess.m_handleSlave = -1;
}
if (m_shellProcess.m_handleMaster >= 0) {
::close(m_shellProcess.m_handleMaster);
m_shellProcess.m_handleMaster = -1;
}
if (m_shellProcess.state() == QProcess::Running) {
m_readMasterNotify->disconnect();
m_readMasterNotify->deleteLater();
m_shellProcess.terminate();
m_shellProcess.waitForFinished(1000);
if (m_shellProcess.state() == QProcess::Running) {
QProcess::startDetached(QString("kill -9 %1").arg(pid()));
m_shellProcess.kill();
m_shellProcess.waitForFinished(1000);
}
return (m_shellProcess.state() == QProcess::NotRunning);
}
return false;
}
IPtyProcess::PtyType UnixPtyProcess::type()
{
return IPtyProcess::UnixPty;
}
QString UnixPtyProcess::dumpDebugInfo()
{
#ifdef PTYQT_DEBUG
return QString("PID: %1, In: %2, Out: %3, Type: %4, Cols: %5, Rows: %6, IsRunning: %7, Shell: "
"%8, SlaveName: %9")
.arg(m_pid)
.arg(m_shellProcess.m_handleMaster)
.arg(m_shellProcess.m_handleSlave)
.arg(type())
.arg(m_size.first)
.arg(m_size.second)
.arg(m_shellProcess.state() == QProcess::Running)
.arg(m_shellPath)
.arg(m_shellProcess.m_handleSlaveName);
#else
return QString("Nothing...");
#endif
}
QIODevice *UnixPtyProcess::notifier()
{
return &m_shellProcess;
}
QByteArray UnixPtyProcess::readAll()
{
QByteArray tmpBuffer = m_shellReadBuffer;
m_shellReadBuffer.clear();
return tmpBuffer;
}
qint64 UnixPtyProcess::write(const QByteArray &byteArray)
{
int result = ::write(m_shellProcess.m_handleMaster, byteArray.constData(), byteArray.size());
Q_UNUSED(result)
return byteArray.size();
}
bool UnixPtyProcess::isAvailable()
{
//todo check something more if required
return true;
}
void UnixPtyProcess::moveToThread(QThread *targetThread)
{
m_shellProcess.moveToThread(targetThread);
}
void ShellProcess::configChildProcess()
{
dup2(m_handleSlave, STDIN_FILENO);
dup2(m_handleSlave, STDOUT_FILENO);
dup2(m_handleSlave, STDERR_FILENO);
pid_t sid = setsid();
ioctl(m_handleSlave, TIOCSCTTY, 0);
tcsetpgrp(m_handleSlave, sid);
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_FREEBSD)
// on Android imposible to put record to the 'utmp' file
struct utmpx utmpxInfo;
memset(&utmpxInfo, 0, sizeof(utmpxInfo));
strncpy(utmpxInfo.ut_user, qgetenv("USER"), sizeof(utmpxInfo.ut_user));
QString device(m_handleSlaveName);
if (device.startsWith("/dev/"))
device = device.mid(5);
const char *d = device.toLatin1().constData();
strncpy(utmpxInfo.ut_line, d, sizeof(utmpxInfo.ut_line));
strncpy(utmpxInfo.ut_id, d + strlen(d) - sizeof(utmpxInfo.ut_id), sizeof(utmpxInfo.ut_id));
struct timeval tv;
gettimeofday(&tv, 0);
utmpxInfo.ut_tv.tv_sec = tv.tv_sec;
utmpxInfo.ut_tv.tv_usec = tv.tv_usec;
utmpxInfo.ut_type = USER_PROCESS;
utmpxInfo.ut_pid = getpid();
utmpxname(_PATH_UTMPX);
setutxent();
pututxline(&utmpxInfo);
endutxent();
#if !defined(Q_OS_UNIX)
updwtmpx(_PATH_UTMPX, &loginInfo);
#endif
#endif
}

View File

@@ -0,0 +1,66 @@
#ifndef UNIXPTYPROCESS_H
#define UNIXPTYPROCESS_H
#include "iptyprocess.h"
#include <QProcess>
#include <QSocketNotifier>
// support for build with MUSL on Alpine Linux
#ifndef _PATH_UTMPX
#include <sys/time.h>
#define _PATH_UTMPX "/var/log/utmp"
#endif
class ShellProcess : public QProcess
{
friend class UnixPtyProcess;
Q_OBJECT
public:
ShellProcess()
: QProcess()
, m_handleMaster(-1)
, m_handleSlave(-1)
{
setProcessChannelMode(QProcess::SeparateChannels);
setChildProcessModifier([this]() { configChildProcess(); });
}
void emitReadyRead() { emit readyRead(); }
protected:
void configChildProcess();
private:
int m_handleMaster, m_handleSlave;
QString m_handleSlaveName;
};
class UnixPtyProcess : public IPtyProcess
{
public:
UnixPtyProcess();
virtual ~UnixPtyProcess();
virtual bool startProcess(const QString &executable,
const QStringList &arguments,
const QString &workingDir,
QStringList environment,
qint16 cols,
qint16 rows);
virtual bool resize(qint16 cols, qint16 rows);
virtual bool kill();
virtual PtyType type();
virtual QString dumpDebugInfo();
virtual QIODevice *notifier();
virtual QByteArray readAll();
virtual qint64 write(const QByteArray &byteArray);
virtual bool isAvailable();
void moveToThread(QThread *targetThread);
private:
ShellProcess m_shellProcess;
QSocketNotifier *m_readMasterNotify;
QByteArray m_shellReadBuffer;
};
#endif // UNIXPTYPROCESS_H

View File

@@ -0,0 +1,275 @@
#include "winptyprocess.h"
#include <QFile>
#include <QFileInfo>
#include <sstream>
#include <QCoreApplication>
#define DEBUG_VAR_LEGACY "WINPTYDBG"
#define DEBUG_VAR_ACTUAL "WINPTY_DEBUG"
#define SHOW_CONSOLE_VAR "WINPTY_SHOW_CONSOLE"
#define WINPTY_AGENT_NAME "winpty-agent.exe"
#define WINPTY_DLL_NAME "winpty.dll"
QString castErrorToString(winpty_error_ptr_t error_ptr)
{
return QString::fromStdWString(winpty_error_msg(error_ptr));
}
WinPtyProcess::WinPtyProcess()
: IPtyProcess()
, m_ptyHandler(nullptr)
, m_innerHandle(nullptr)
, m_inSocket(nullptr)
, m_outSocket(nullptr)
{
#ifdef PTYQT_DEBUG
m_trace = true;
#endif
}
WinPtyProcess::~WinPtyProcess()
{
kill();
}
bool WinPtyProcess::startProcess(const QString &executable,
const QStringList &arguments,
const QString &workingDir,
QStringList environment,
qint16 cols,
qint16 rows)
{
if (!isAvailable())
{
m_lastError = QString("WinPty Error: winpty-agent.exe or winpty.dll not found!");
return false;
}
//already running
if (m_ptyHandler != nullptr)
return false;
QFileInfo fi(executable);
if (fi.isRelative() || !QFile::exists(executable))
{
//todo add auto-find executable in PATH env var
m_lastError = QString("WinPty Error: shell file path must be absolute");
return false;
}
m_shellPath = executable;
m_size = QPair<qint16, qint16>(cols, rows);
#ifdef PTYQT_DEBUG
if (m_trace)
{
environment.append(QString("%1=1").arg(DEBUG_VAR_LEGACY));
environment.append(QString("%1=trace").arg(DEBUG_VAR_ACTUAL));
environment.append(QString("%1=1").arg(SHOW_CONSOLE_VAR));
SetEnvironmentVariableA(DEBUG_VAR_LEGACY, "1");
SetEnvironmentVariableA(DEBUG_VAR_ACTUAL, "trace");
SetEnvironmentVariableA(SHOW_CONSOLE_VAR, "1");
}
#endif
//env
std::wstringstream envBlock;
foreach (QString line, environment)
{
envBlock << line.toStdWString() << L'\0';
}
std::wstring env = envBlock.str();
//create start config
winpty_error_ptr_t errorPtr = nullptr;
winpty_config_t* startConfig = winpty_config_new(0, &errorPtr);
if (startConfig == nullptr)
{
m_lastError = QString("WinPty Error: create start config -> %1").arg(castErrorToString(errorPtr));
return false;
}
winpty_error_free(errorPtr);
//set params
winpty_config_set_initial_size(startConfig, cols, rows);
winpty_config_set_mouse_mode(startConfig, WINPTY_MOUSE_MODE_AUTO);
//winpty_config_set_agent_timeout();
//start agent
m_ptyHandler = winpty_open(startConfig, &errorPtr);
winpty_config_free(startConfig); //start config is local var, free it after use
if (m_ptyHandler == nullptr)
{
m_lastError = QString("WinPty Error: start agent -> %1").arg(castErrorToString(errorPtr));
return false;
}
winpty_error_free(errorPtr);
//create spawn config
winpty_spawn_config_t* spawnConfig = winpty_spawn_config_new(WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, m_shellPath.toStdWString().c_str(),
//commandLine.toStdWString().c_str(), cwd.toStdWString().c_str(),
arguments.join(" ").toStdWString().c_str(), workingDir.toStdWString().c_str(),
env.c_str(),
&errorPtr);
if (spawnConfig == nullptr)
{
m_lastError = QString("WinPty Error: create spawn config -> %1").arg(castErrorToString(errorPtr));
return false;
}
winpty_error_free(errorPtr);
//spawn the new process
BOOL spawnSuccess = winpty_spawn(m_ptyHandler, spawnConfig, &m_innerHandle, nullptr, nullptr, &errorPtr);
winpty_spawn_config_free(spawnConfig); //spawn config is local var, free it after use
if (!spawnSuccess)
{
m_lastError = QString("WinPty Error: start terminal process -> %1").arg(castErrorToString(errorPtr));
return false;
}
winpty_error_free(errorPtr);
m_pid = (int)GetProcessId(m_innerHandle);
// Notify when the shell process has been terminated
RegisterWaitForSingleObject(
&m_shellCloseWaitHandle,
m_innerHandle,
[](PVOID data, BOOLEAN) {
auto self = static_cast<WinPtyProcess *>(data);
// Do not respawn if the object is about to be destructed
DWORD exitCode = 0;
GetExitCodeProcess(self->m_innerHandle, &exitCode);
self->m_exitCode = exitCode;
if (!self->m_aboutToDestruct)
emit self->notifier()->aboutToClose();
},
this,
INFINITE,
WT_EXECUTEONLYONCE);
//get pipe names
LPCWSTR conInPipeName = winpty_conin_name(m_ptyHandler);
m_conInName = QString::fromStdWString(std::wstring(conInPipeName));
m_inSocket = new QLocalSocket();
m_inSocket->connectToServer(m_conInName, QIODevice::WriteOnly);
m_inSocket->waitForConnected();
LPCWSTR conOutPipeName = winpty_conout_name(m_ptyHandler);
m_conOutName = QString::fromStdWString(std::wstring(conOutPipeName));
m_outSocket = new QLocalSocket();
m_outSocket->connectToServer(m_conOutName, QIODevice::ReadOnly);
m_outSocket->waitForConnected();
if (m_inSocket->state() != QLocalSocket::ConnectedState && m_outSocket->state() != QLocalSocket::ConnectedState)
{
m_lastError = QString("WinPty Error: Unable to connect local sockets -> %1 / %2").arg(m_inSocket->errorString()).arg(m_outSocket->errorString());
m_inSocket->deleteLater();
m_outSocket->deleteLater();
m_inSocket = nullptr;
m_outSocket = nullptr;
return false;
}
return true;
}
bool WinPtyProcess::resize(qint16 cols, qint16 rows)
{
if (m_ptyHandler == nullptr)
{
return false;
}
bool res = winpty_set_size(m_ptyHandler, cols, rows, nullptr);
if (res)
{
m_size = QPair<qint16, qint16>(cols, rows);
}
return res;
}
bool WinPtyProcess::kill()
{
bool exitCode = false;
if (m_innerHandle != nullptr && m_ptyHandler != nullptr) {
m_aboutToDestruct = true;
//disconnect all signals (readyRead, ...)
m_inSocket->disconnect();
m_outSocket->disconnect();
//disconnect for server
m_inSocket->disconnectFromServer();
m_outSocket->disconnectFromServer();
m_inSocket->deleteLater();
m_outSocket->deleteLater();
m_inSocket = nullptr;
m_outSocket = nullptr;
winpty_free(m_ptyHandler);
exitCode = CloseHandle(m_innerHandle);
UnregisterWait(m_shellCloseWaitHandle);
m_ptyHandler = nullptr;
m_innerHandle = nullptr;
m_conInName = QString();
m_conOutName = QString();
m_pid = 0;
}
return exitCode;
}
IPtyProcess::PtyType WinPtyProcess::type()
{
return PtyType::WinPty;
}
QString WinPtyProcess::dumpDebugInfo()
{
#ifdef PTYQT_DEBUG
return QString("PID: %1, ConIn: %2, ConOut: %3, Type: %4, Cols: %5, Rows: %6, IsRunning: %7, Shell: %8")
.arg(m_pid).arg(m_conInName).arg(m_conOutName).arg(type())
.arg(m_size.first).arg(m_size.second).arg(m_ptyHandler != nullptr)
.arg(m_shellPath);
#else
return QString("Nothing...");
#endif
}
QIODevice *WinPtyProcess::notifier()
{
return m_outSocket;
}
QByteArray WinPtyProcess::readAll()
{
return m_outSocket->readAll();
}
qint64 WinPtyProcess::write(const QByteArray &byteArray)
{
return m_inSocket->write(byteArray);
}
bool WinPtyProcess::isAvailable()
{
#ifdef PTYQT_BUILD_STATIC
return QFile::exists(QCoreApplication::applicationDirPath() + "/" + WINPTY_AGENT_NAME);
#elif PTYQT_BUILD_DYNAMIC
return QFile::exists(QCoreApplication::applicationDirPath() + "/" + WINPTY_AGENT_NAME)
&& QFile::exists(QCoreApplication::applicationDirPath() + "/" + WINPTY_DLL_NAME);
#endif
return true;
}
void WinPtyProcess::moveToThread(QThread *targetThread)
{
m_inSocket->moveToThread(targetThread);
m_outSocket->moveToThread(targetThread);
}

View File

@@ -0,0 +1,42 @@
#ifndef WINPTYPROCESS_H
#define WINPTYPROCESS_H
#include "iptyprocess.h"
#include "winpty.h"
#include <QLocalSocket>
class WinPtyProcess : public IPtyProcess
{
public:
WinPtyProcess();
~WinPtyProcess();
bool startProcess(const QString &executable,
const QStringList &arguments,
const QString &workingDir,
QStringList environment,
qint16 cols,
qint16 rows);
bool resize(qint16 cols, qint16 rows);
bool kill();
PtyType type();
QString dumpDebugInfo();
QIODevice *notifier();
QByteArray readAll();
qint64 write(const QByteArray &byteArray);
bool isAvailable();
void moveToThread(QThread *targetThread);
private:
winpty_t *m_ptyHandler;
HANDLE m_innerHandle;
QString m_conInName;
QString m_conOutName;
QLocalSocket *m_inSocket;
QLocalSocket *m_outSocket;
bool m_aboutToDestruct{false};
HANDLE m_shellCloseWaitHandle{INVALID_HANDLE_VALUE};
};
#endif // WINPTYPROCESS_H

View File

@@ -0,0 +1,25 @@
add_library(libvterm STATIC
src/encoding.c
src/fullwidth.inc
src/keyboard.c
src/mouse.c
src/parser.c
src/pen.c
src/rect.h
src/screen.c
src/state.c
src/unicode.c
src/utf8.h
src/vterm.c
src/vterm_internal.h
)
target_include_directories(libvterm PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
set_target_properties(libvterm
PROPERTIES
QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON
POSITION_INDEPENDENT_CODE ON 
)

22
src/libs/3rdparty/libvterm/CONTRIBUTING vendored Normal file
View File

@@ -0,0 +1,22 @@
How to Contribute
-----------------
The main resources for this library are:
Launchpad
https://launchpad.net/libvterm
IRC:
##tty or #tickit on irc.libera.chat
Email:
Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
Bug reports and feature requests can be sent to any of the above resources.
New features, bug patches, etc.. should in the first instance be discussed via
any of the resources listed above, before starting work on the actual code.
There may be future plans or development already in-progress that could be
affected so it is better to discuss the ideas first before starting work
actually writing any code.

23
src/libs/3rdparty/libvterm/LICENSE vendored Normal file
View File

@@ -0,0 +1,23 @@
The MIT License
Copyright (c) 2008 Paul Evans <leonerd@leonerd.org.uk>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,635 @@
#ifndef __VTERM_H__
#define __VTERM_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "vterm_keycodes.h"
#define VTERM_VERSION_MAJOR 0
#define VTERM_VERSION_MINOR 3
#define VTERM_CHECK_VERSION \
vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR)
/* Any cell can contain at most one basic printing character and 5 combining
* characters. This number could be changed but will be ABI-incompatible if
* you do */
#define VTERM_MAX_CHARS_PER_CELL 6
typedef struct VTerm VTerm;
typedef struct VTermState VTermState;
typedef struct VTermScreen VTermScreen;
typedef struct {
int row;
int col;
} VTermPos;
/* some small utility functions; we can just keep these static here */
/* order points by on-screen flow order */
static inline int vterm_pos_cmp(VTermPos a, VTermPos b)
{
return (a.row == b.row) ? a.col - b.col : a.row - b.row;
}
typedef struct {
int start_row;
int end_row;
int start_col;
int end_col;
} VTermRect;
/* true if the rect contains the point */
static inline int vterm_rect_contains(VTermRect r, VTermPos p)
{
return p.row >= r.start_row && p.row < r.end_row &&
p.col >= r.start_col && p.col < r.end_col;
}
/* move a rect */
static inline void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta)
{
rect->start_row += row_delta; rect->end_row += row_delta;
rect->start_col += col_delta; rect->end_col += col_delta;
}
/**
* Bit-field describing the content of the tagged union `VTermColor`.
*/
typedef enum {
/**
* If the lower bit of `type` is not set, the colour is 24-bit RGB.
*/
VTERM_COLOR_RGB = 0x00,
/**
* The colour is an index into a palette of 256 colours.
*/
VTERM_COLOR_INDEXED = 0x01,
/**
* Mask that can be used to extract the RGB/Indexed bit.
*/
VTERM_COLOR_TYPE_MASK = 0x01,
/**
* If set, indicates that this colour should be the default foreground
* color, i.e. there was no SGR request for another colour. When
* rendering this colour it is possible to ignore "idx" and just use a
* colour that is not in the palette.
*/
VTERM_COLOR_DEFAULT_FG = 0x02,
/**
* If set, indicates that this colour should be the default background
* color, i.e. there was no SGR request for another colour. A common
* option when rendering this colour is to not render a background at
* all, for example by rendering the window transparently at this spot.
*/
VTERM_COLOR_DEFAULT_BG = 0x04,
/**
* Mask that can be used to extract the default foreground/background bit.
*/
VTERM_COLOR_DEFAULT_MASK = 0x06
} VTermColorType;
/**
* Returns true if the VTERM_COLOR_RGB `type` flag is set, indicating that the
* given VTermColor instance is an indexed colour.
*/
#define VTERM_COLOR_IS_INDEXED(col) \
(((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_INDEXED)
/**
* Returns true if the VTERM_COLOR_INDEXED `type` flag is set, indicating that
* the given VTermColor instance is an rgb colour.
*/
#define VTERM_COLOR_IS_RGB(col) \
(((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_RGB)
/**
* Returns true if the VTERM_COLOR_DEFAULT_FG `type` flag is set, indicating
* that the given VTermColor instance corresponds to the default foreground
* color.
*/
#define VTERM_COLOR_IS_DEFAULT_FG(col) \
(!!((col)->type & VTERM_COLOR_DEFAULT_FG))
/**
* Returns true if the VTERM_COLOR_DEFAULT_BG `type` flag is set, indicating
* that the given VTermColor instance corresponds to the default background
* color.
*/
#define VTERM_COLOR_IS_DEFAULT_BG(col) \
(!!((col)->type & VTERM_COLOR_DEFAULT_BG))
/**
* Tagged union storing either an RGB color or an index into a colour palette.
* In order to convert indexed colours to RGB, you may use the
* vterm_state_convert_color_to_rgb() or vterm_screen_convert_color_to_rgb()
* functions which lookup the RGB colour from the palette maintained by a
* VTermState or VTermScreen instance.
*/
typedef union {
/**
* Tag indicating which union member is actually valid. This variable
* coincides with the `type` member of the `rgb` and the `indexed` struct
* in memory. Please use the `VTERM_COLOR_IS_*` test macros to check whether
* a particular type flag is set.
*/
uint8_t type;
/**
* Valid if `VTERM_COLOR_IS_RGB(type)` is true. Holds the RGB colour values.
*/
struct {
/**
* Same as the top-level `type` member stored in VTermColor.
*/
uint8_t type;
/**
* The actual 8-bit red, green, blue colour values.
*/
uint8_t red, green, blue;
} rgb;
/**
* If `VTERM_COLOR_IS_INDEXED(type)` is true, this member holds the index into
* the colour palette.
*/
struct {
/**
* Same as the top-level `type` member stored in VTermColor.
*/
uint8_t type;
/**
* Index into the colour map.
*/
uint8_t idx;
} indexed;
} VTermColor;
/**
* Constructs a new VTermColor instance representing the given RGB values.
*/
static inline void vterm_color_rgb(VTermColor *col, uint8_t red, uint8_t green,
uint8_t blue)
{
col->type = VTERM_COLOR_RGB;
col->rgb.red = red;
col->rgb.green = green;
col->rgb.blue = blue;
}
/**
* Construct a new VTermColor instance representing an indexed color with the
* given index.
*/
static inline void vterm_color_indexed(VTermColor *col, uint8_t idx)
{
col->type = VTERM_COLOR_INDEXED;
col->indexed.idx = idx;
}
/**
* Compares two colours. Returns true if the colors are equal, false otherwise.
*/
int vterm_color_is_equal(const VTermColor *a, const VTermColor *b);
typedef enum {
/* VTERM_VALUETYPE_NONE = 0 */
VTERM_VALUETYPE_BOOL = 1,
VTERM_VALUETYPE_INT,
VTERM_VALUETYPE_STRING,
VTERM_VALUETYPE_COLOR,
VTERM_N_VALUETYPES
} VTermValueType;
typedef struct {
const char *str;
size_t len : 30;
bool initial : 1;
bool final : 1;
} VTermStringFragment;
typedef union {
int boolean;
int number;
VTermStringFragment string;
VTermColor color;
} VTermValue;
typedef enum {
/* VTERM_ATTR_NONE = 0 */
VTERM_ATTR_BOLD = 1, // bool: 1, 22
VTERM_ATTR_UNDERLINE, // number: 4, 21, 24
VTERM_ATTR_ITALIC, // bool: 3, 23
VTERM_ATTR_BLINK, // bool: 5, 25
VTERM_ATTR_REVERSE, // bool: 7, 27
VTERM_ATTR_CONCEAL, // bool: 8, 28
VTERM_ATTR_STRIKE, // bool: 9, 29
VTERM_ATTR_FONT, // number: 10-19
VTERM_ATTR_FOREGROUND, // color: 30-39 90-97
VTERM_ATTR_BACKGROUND, // color: 40-49 100-107
VTERM_ATTR_SMALL, // bool: 73, 74, 75
VTERM_ATTR_BASELINE, // number: 73, 74, 75
VTERM_N_ATTRS
} VTermAttr;
typedef enum {
/* VTERM_PROP_NONE = 0 */
VTERM_PROP_CURSORVISIBLE = 1, // bool
VTERM_PROP_CURSORBLINK, // bool
VTERM_PROP_ALTSCREEN, // bool
VTERM_PROP_TITLE, // string
VTERM_PROP_ICONNAME, // string
VTERM_PROP_REVERSE, // bool
VTERM_PROP_CURSORSHAPE, // number
VTERM_PROP_MOUSE, // number
VTERM_N_PROPS
} VTermProp;
enum {
VTERM_PROP_CURSORSHAPE_BLOCK = 1,
VTERM_PROP_CURSORSHAPE_UNDERLINE,
VTERM_PROP_CURSORSHAPE_BAR_LEFT,
VTERM_N_PROP_CURSORSHAPES
};
enum {
VTERM_PROP_MOUSE_NONE = 0,
VTERM_PROP_MOUSE_CLICK,
VTERM_PROP_MOUSE_DRAG,
VTERM_PROP_MOUSE_MOVE,
VTERM_N_PROP_MOUSES
};
typedef enum {
VTERM_SELECTION_CLIPBOARD = (1<<0),
VTERM_SELECTION_PRIMARY = (1<<1),
VTERM_SELECTION_SECONDARY = (1<<2),
VTERM_SELECTION_SELECT = (1<<3),
VTERM_SELECTION_CUT0 = (1<<4), /* also CUT1 .. CUT7 by bitshifting */
} VTermSelectionMask;
typedef struct {
const uint32_t *chars;
int width;
unsigned int protected_cell:1; /* DECSCA-protected against DECSEL/DECSED */
unsigned int dwl:1; /* DECDWL or DECDHL double-width line */
unsigned int dhl:2; /* DECDHL double-height line (1=top 2=bottom) */
} VTermGlyphInfo;
typedef struct {
unsigned int doublewidth:1; /* DECDWL or DECDHL line */
unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */
unsigned int continuation:1; /* Line is a flow continuation of the previous */
} VTermLineInfo;
/* Copies of VTermState fields that the 'resize' callback might have reason to
* edit. 'resize' callback gets total control of these fields and may
* free-and-reallocate them if required. They will be copied back from the
* struct after the callback has returned.
*/
typedef struct {
VTermPos pos; /* current cursor position */
VTermLineInfo *lineinfos[2]; /* [1] may be NULL */
} VTermStateFields;
typedef struct {
/* libvterm relies on this memory to be zeroed out before it is returned
* by the allocator. */
void *(*malloc)(size_t size, void *allocdata);
void (*free)(void *ptr, void *allocdata);
} VTermAllocatorFunctions;
void vterm_check_version(int major, int minor);
struct VTermBuilder {
int ver; /* currently unused but reserved for some sort of ABI version flag */
int rows, cols;
const VTermAllocatorFunctions *allocator;
void *allocdata;
/* Override default sizes for various structures */
size_t outbuffer_len; /* default: 4096 */
size_t tmpbuffer_len; /* default: 4096 */
};
VTerm *vterm_build(const struct VTermBuilder *builder);
/* A convenient shortcut for default cases */
VTerm *vterm_new(int rows, int cols);
/* This shortcuts are generally discouraged in favour of just using vterm_build() */
VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata);
void vterm_free(VTerm* vt);
void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp);
void vterm_set_size(VTerm *vt, int rows, int cols);
int vterm_get_utf8(const VTerm *vt);
void vterm_set_utf8(VTerm *vt, int is_utf8);
size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len);
/* Setting output callback will override the buffer logic */
typedef void VTermOutputCallback(const char *s, size_t len, void *user);
void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user);
/* These buffer functions only work if output callback is NOT set
* These are deprecated and will be removed in a later version */
size_t vterm_output_get_buffer_size(const VTerm *vt);
size_t vterm_output_get_buffer_current(const VTerm *vt);
size_t vterm_output_get_buffer_remaining(const VTerm *vt);
/* This too */
size_t vterm_output_read(VTerm *vt, char *buffer, size_t len);
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod);
void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod);
void vterm_keyboard_start_paste(VTerm *vt);
void vterm_keyboard_end_paste(VTerm *vt);
void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod);
void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod);
// ------------
// Parser layer
// ------------
/* Flag to indicate non-final subparameters in a single CSI parameter.
* Consider
* CSI 1;2:3:4;5a
* 1 4 and 5 are final.
* 2 and 3 are non-final and will have this bit set
*
* Don't confuse this with the final byte of the CSI escape; 'a' in this case.
*/
#define CSI_ARG_FLAG_MORE (1U<<31)
#define CSI_ARG_MASK (~(1U<<31))
#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE)
#define CSI_ARG(a) ((a) & CSI_ARG_MASK)
/* Can't use -1 to indicate a missing argument; use this instead */
#define CSI_ARG_MISSING ((1UL<<31)-1)
#define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING)
#define CSI_ARG_OR(a,def) (CSI_ARG(a) == CSI_ARG_MISSING ? (def) : CSI_ARG(a))
#define CSI_ARG_COUNT(a) (CSI_ARG(a) == CSI_ARG_MISSING || CSI_ARG(a) == 0 ? 1 : CSI_ARG(a))
typedef struct {
int (*text)(const char *bytes, size_t len, void *user);
int (*control)(unsigned char control, void *user);
int (*escape)(const char *bytes, size_t len, void *user);
int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
int (*osc)(int command, VTermStringFragment frag, void *user);
int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user);
int (*apc)(VTermStringFragment frag, void *user);
int (*pm)(VTermStringFragment frag, void *user);
int (*sos)(VTermStringFragment frag, void *user);
int (*resize)(int rows, int cols, void *user);
} VTermParserCallbacks;
void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user);
void *vterm_parser_get_cbdata(VTerm *vt);
/* Normally NUL, CAN, SUB and DEL are ignored. Setting this true causes them
* to be emitted by the 'control' callback
*/
void vterm_parser_set_emit_nul(VTerm *vt, bool emit);
// -----------
// State layer
// -----------
typedef struct {
int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user);
int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
int (*scrollrect)(VTermRect rect, int downward, int rightward, void *user);
int (*moverect)(VTermRect dest, VTermRect src, void *user);
int (*erase)(VTermRect rect, int selective, void *user);
int (*initpen)(void *user);
int (*setpenattr)(VTermAttr attr, VTermValue *val, void *user);
int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
int (*bell)(void *user);
int (*resize)(int rows, int cols, VTermStateFields *fields, void *user);
int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user);
int (*sb_clear)(void *user);
} VTermStateCallbacks;
typedef struct {
int (*control)(unsigned char control, void *user);
int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
int (*osc)(int command, VTermStringFragment frag, void *user);
int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user);
int (*apc)(VTermStringFragment frag, void *user);
int (*pm)(VTermStringFragment frag, void *user);
int (*sos)(VTermStringFragment frag, void *user);
} VTermStateFallbacks;
typedef struct {
int (*set)(VTermSelectionMask mask, VTermStringFragment frag, void *user);
int (*query)(VTermSelectionMask mask, void *user);
} VTermSelectionCallbacks;
VTermState *vterm_obtain_state(VTerm *vt);
void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user);
void *vterm_state_get_cbdata(VTermState *state);
void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermStateFallbacks *fallbacks, void *user);
void *vterm_state_get_unrecognised_fbdata(VTermState *state);
void vterm_state_reset(VTermState *state, int hard);
void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos);
void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg);
void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col);
void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg);
void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col);
void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright);
int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val);
int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val);
void vterm_state_focus_in(VTermState *state);
void vterm_state_focus_out(VTermState *state);
const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row);
/**
* Makes sure that the given color `col` is indeed an RGB colour. After this
* function returns, VTERM_COLOR_IS_RGB(col) will return true, while all other
* flags stored in `col->type` will have been reset.
*
* @param state is the VTermState instance from which the colour palette should
* be extracted.
* @param col is a pointer at the VTermColor instance that should be converted
* to an RGB colour.
*/
void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col);
void vterm_state_set_selection_callbacks(VTermState *state, const VTermSelectionCallbacks *callbacks, void *user,
char *buffer, size_t buflen);
void vterm_state_send_selection(VTermState *state, VTermSelectionMask mask, VTermStringFragment frag);
// ------------
// Screen layer
// ------------
typedef struct {
unsigned int bold : 1;
unsigned int underline : 2;
unsigned int italic : 1;
unsigned int blink : 1;
unsigned int reverse : 1;
unsigned int conceal : 1;
unsigned int strike : 1;
unsigned int font : 4; /* 0 to 9 */
unsigned int dwl : 1; /* On a DECDWL or DECDHL line */
unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */
unsigned int small : 1;
unsigned int baseline : 2;
} VTermScreenCellAttrs;
enum {
VTERM_UNDERLINE_OFF,
VTERM_UNDERLINE_SINGLE,
VTERM_UNDERLINE_DOUBLE,
VTERM_UNDERLINE_CURLY,
};
enum {
VTERM_BASELINE_NORMAL,
VTERM_BASELINE_RAISE,
VTERM_BASELINE_LOWER,
};
typedef struct {
uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
char width;
VTermScreenCellAttrs attrs;
VTermColor fg, bg;
} VTermScreenCell;
typedef struct {
int (*damage)(VTermRect rect, void *user);
int (*moverect)(VTermRect dest, VTermRect src, void *user);
int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);
int (*settermprop)(VTermProp prop, VTermValue *val, void *user);
int (*bell)(void *user);
int (*resize)(int rows, int cols, void *user);
int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user);
int (*sb_popline)(int cols, VTermScreenCell *cells, void *user);
int (*sb_clear)(void* user);
} VTermScreenCallbacks;
VTermScreen *vterm_obtain_screen(VTerm *vt);
void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user);
void *vterm_screen_get_cbdata(VTermScreen *screen);
void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user);
void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen);
void vterm_screen_enable_reflow(VTermScreen *screen, bool reflow);
// Back-compat alias for the brief time it was in 0.3-RC1
#define vterm_screen_set_reflow vterm_screen_enable_reflow
void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen);
typedef enum {
VTERM_DAMAGE_CELL, /* every cell */
VTERM_DAMAGE_ROW, /* entire rows */
VTERM_DAMAGE_SCREEN, /* entire screen */
VTERM_DAMAGE_SCROLL, /* entire screen + scrollrect */
VTERM_N_DAMAGES
} VTermDamageSize;
void vterm_screen_flush_damage(VTermScreen *screen);
void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size);
void vterm_screen_reset(VTermScreen *screen, int hard);
/* Neither of these functions NUL-terminate the buffer */
size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect);
size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect);
typedef enum {
VTERM_ATTR_BOLD_MASK = 1 << 0,
VTERM_ATTR_UNDERLINE_MASK = 1 << 1,
VTERM_ATTR_ITALIC_MASK = 1 << 2,
VTERM_ATTR_BLINK_MASK = 1 << 3,
VTERM_ATTR_REVERSE_MASK = 1 << 4,
VTERM_ATTR_STRIKE_MASK = 1 << 5,
VTERM_ATTR_FONT_MASK = 1 << 6,
VTERM_ATTR_FOREGROUND_MASK = 1 << 7,
VTERM_ATTR_BACKGROUND_MASK = 1 << 8,
VTERM_ATTR_CONCEAL_MASK = 1 << 9,
VTERM_ATTR_SMALL_MASK = 1 << 10,
VTERM_ATTR_BASELINE_MASK = 1 << 11,
VTERM_ALL_ATTRS_MASK = (1 << 12) - 1
} VTermAttrMask;
int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs);
int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell);
int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos);
/**
* Same as vterm_state_convert_color_to_rgb(), but takes a `screen` instead of a `state`
* instance.
*/
void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col);
/**
* Similar to vterm_state_set_default_colors(), but also resets colours in the
* screen buffer(s)
*/
void vterm_screen_set_default_colors(VTermScreen *screen, const VTermColor *default_fg, const VTermColor *default_bg);
// ---------
// Utilities
// ---------
VTermValueType vterm_get_attr_type(VTermAttr attr);
VTermValueType vterm_get_prop_type(VTermProp prop);
void vterm_scroll_rect(VTermRect rect,
int downward,
int rightward,
int (*moverect)(VTermRect src, VTermRect dest, void *user),
int (*eraserect)(VTermRect rect, int selective, void *user),
void *user);
void vterm_copy_cells(VTermRect dest,
VTermRect src,
void (*copycell)(VTermPos dest, VTermPos src, void *user),
void *user);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,61 @@
#ifndef __VTERM_INPUT_H__
#define __VTERM_INPUT_H__
typedef enum {
VTERM_MOD_NONE = 0x00,
VTERM_MOD_SHIFT = 0x01,
VTERM_MOD_ALT = 0x02,
VTERM_MOD_CTRL = 0x04,
VTERM_ALL_MODS_MASK = 0x07
} VTermModifier;
typedef enum {
VTERM_KEY_NONE,
VTERM_KEY_ENTER,
VTERM_KEY_TAB,
VTERM_KEY_BACKSPACE,
VTERM_KEY_ESCAPE,
VTERM_KEY_UP,
VTERM_KEY_DOWN,
VTERM_KEY_LEFT,
VTERM_KEY_RIGHT,
VTERM_KEY_INS,
VTERM_KEY_DEL,
VTERM_KEY_HOME,
VTERM_KEY_END,
VTERM_KEY_PAGEUP,
VTERM_KEY_PAGEDOWN,
VTERM_KEY_FUNCTION_0 = 256,
VTERM_KEY_FUNCTION_MAX = VTERM_KEY_FUNCTION_0 + 255,
VTERM_KEY_KP_0,
VTERM_KEY_KP_1,
VTERM_KEY_KP_2,
VTERM_KEY_KP_3,
VTERM_KEY_KP_4,
VTERM_KEY_KP_5,
VTERM_KEY_KP_6,
VTERM_KEY_KP_7,
VTERM_KEY_KP_8,
VTERM_KEY_KP_9,
VTERM_KEY_KP_MULT,
VTERM_KEY_KP_PLUS,
VTERM_KEY_KP_COMMA,
VTERM_KEY_KP_MINUS,
VTERM_KEY_KP_PERIOD,
VTERM_KEY_KP_DIVIDE,
VTERM_KEY_KP_ENTER,
VTERM_KEY_KP_EQUAL,
VTERM_KEY_MAX, // Must be last
VTERM_N_KEYS = VTERM_KEY_MAX
} VTermKey;
#define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n))
#endif

View File

@@ -0,0 +1,230 @@
#include "vterm_internal.h"
#define UNICODE_INVALID 0xFFFD
#if defined(DEBUG) && DEBUG > 1
# define DEBUG_PRINT_UTF8
#endif
struct UTF8DecoderData {
// number of bytes remaining in this codepoint
int bytes_remaining;
// number of bytes total in this codepoint once it's finished
// (for detecting overlongs)
int bytes_total;
int this_cp;
};
static void init_utf8(VTermEncoding *enc, void *data_)
{
struct UTF8DecoderData *data = data_;
data->bytes_remaining = 0;
data->bytes_total = 0;
}
static void decode_utf8(VTermEncoding *enc, void *data_,
uint32_t cp[], int *cpi, int cplen,
const char bytes[], size_t *pos, size_t bytelen)
{
struct UTF8DecoderData *data = data_;
#ifdef DEBUG_PRINT_UTF8
printf("BEGIN UTF-8\n");
#endif
for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
unsigned char c = bytes[*pos];
#ifdef DEBUG_PRINT_UTF8
printf(" pos=%zd c=%02x rem=%d\n", *pos, c, data->bytes_remaining);
#endif
if(c < 0x20) // C0
return;
else if(c >= 0x20 && c < 0x7f) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
cp[(*cpi)++] = c;
#ifdef DEBUG_PRINT_UTF8
printf(" UTF-8 char: U+%04x\n", c);
#endif
data->bytes_remaining = 0;
}
else if(c == 0x7f) // DEL
return;
else if(c >= 0x80 && c < 0xc0) {
if(!data->bytes_remaining) {
cp[(*cpi)++] = UNICODE_INVALID;
continue;
}
data->this_cp <<= 6;
data->this_cp |= c & 0x3f;
data->bytes_remaining--;
if(!data->bytes_remaining) {
#ifdef DEBUG_PRINT_UTF8
printf(" UTF-8 raw char U+%04x bytelen=%d ", data->this_cp, data->bytes_total);
#endif
// Check for overlong sequences
switch(data->bytes_total) {
case 2:
if(data->this_cp < 0x0080) data->this_cp = UNICODE_INVALID;
break;
case 3:
if(data->this_cp < 0x0800) data->this_cp = UNICODE_INVALID;
break;
case 4:
if(data->this_cp < 0x10000) data->this_cp = UNICODE_INVALID;
break;
case 5:
if(data->this_cp < 0x200000) data->this_cp = UNICODE_INVALID;
break;
case 6:
if(data->this_cp < 0x4000000) data->this_cp = UNICODE_INVALID;
break;
}
// Now look for plain invalid ones
if((data->this_cp >= 0xD800 && data->this_cp <= 0xDFFF) ||
data->this_cp == 0xFFFE ||
data->this_cp == 0xFFFF)
data->this_cp = UNICODE_INVALID;
#ifdef DEBUG_PRINT_UTF8
printf(" char: U+%04x\n", data->this_cp);
#endif
cp[(*cpi)++] = data->this_cp;
}
}
else if(c >= 0xc0 && c < 0xe0) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x1f;
data->bytes_total = 2;
data->bytes_remaining = 1;
}
else if(c >= 0xe0 && c < 0xf0) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x0f;
data->bytes_total = 3;
data->bytes_remaining = 2;
}
else if(c >= 0xf0 && c < 0xf8) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x07;
data->bytes_total = 4;
data->bytes_remaining = 3;
}
else if(c >= 0xf8 && c < 0xfc) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x03;
data->bytes_total = 5;
data->bytes_remaining = 4;
}
else if(c >= 0xfc && c < 0xfe) {
if(data->bytes_remaining)
cp[(*cpi)++] = UNICODE_INVALID;
data->this_cp = c & 0x01;
data->bytes_total = 6;
data->bytes_remaining = 5;
}
else {
cp[(*cpi)++] = UNICODE_INVALID;
}
}
}
static VTermEncoding encoding_utf8 = {
.init = &init_utf8,
.decode = &decode_utf8,
};
static void decode_usascii(VTermEncoding *enc, void *data,
uint32_t cp[], int *cpi, int cplen,
const char bytes[], size_t *pos, size_t bytelen)
{
int is_gr = bytes[*pos] & 0x80;
for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
unsigned char c = bytes[*pos] ^ is_gr;
if(c < 0x20 || c == 0x7f || c >= 0x80)
return;
cp[(*cpi)++] = c;
}
}
static VTermEncoding encoding_usascii = {
.decode = &decode_usascii,
};
struct StaticTableEncoding {
const VTermEncoding enc;
const uint32_t chars[128];
};
static void decode_table(VTermEncoding *enc, void *data,
uint32_t cp[], int *cpi, int cplen,
const char bytes[], size_t *pos, size_t bytelen)
{
struct StaticTableEncoding *table = (struct StaticTableEncoding *)enc;
int is_gr = bytes[*pos] & 0x80;
for(; *pos < bytelen && *cpi < cplen; (*pos)++) {
unsigned char c = bytes[*pos] ^ is_gr;
if(c < 0x20 || c == 0x7f || c >= 0x80)
return;
if(table->chars[c])
cp[(*cpi)++] = table->chars[c];
else
cp[(*cpi)++] = c;
}
}
#include "encoding/DECdrawing.inc"
#include "encoding/uk.inc"
static struct {
VTermEncodingType type;
char designation;
VTermEncoding *enc;
}
encodings[] = {
{ ENC_UTF8, 'u', &encoding_utf8 },
{ ENC_SINGLE_94, '0', (VTermEncoding*)&encoding_DECdrawing },
{ ENC_SINGLE_94, 'A', (VTermEncoding*)&encoding_uk },
{ ENC_SINGLE_94, 'B', &encoding_usascii },
{ 0 },
};
/* This ought to be INTERNAL but isn't because it's used by unit testing */
VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation)
{
for(int i = 0; encodings[i].designation; i++)
if(encodings[i].type == type && encodings[i].designation == designation)
return encodings[i].enc;
return NULL;
}

View File

@@ -0,0 +1,36 @@
static const struct StaticTableEncoding encoding_DECdrawing = {
{ .decode = &decode_table },
{
[0x60] = 0x25C6,
[0x61] = 0x2592,
[0x62] = 0x2409,
[0x63] = 0x240C,
[0x64] = 0x240D,
[0x65] = 0x240A,
[0x66] = 0x00B0,
[0x67] = 0x00B1,
[0x68] = 0x2424,
[0x69] = 0x240B,
[0x6a] = 0x2518,
[0x6b] = 0x2510,
[0x6c] = 0x250C,
[0x6d] = 0x2514,
[0x6e] = 0x253C,
[0x6f] = 0x23BA,
[0x70] = 0x23BB,
[0x71] = 0x2500,
[0x72] = 0x23BC,
[0x73] = 0x23BD,
[0x74] = 0x251C,
[0x75] = 0x2524,
[0x76] = 0x2534,
[0x77] = 0x252C,
[0x78] = 0x2502,
[0x79] = 0x2A7D,
[0x7a] = 0x2A7E,
[0x7b] = 0x03C0,
[0x7c] = 0x2260,
[0x7d] = 0x00A3,
[0x7e] = 0x00B7,
}
};

View File

@@ -0,0 +1,6 @@
static const struct StaticTableEncoding encoding_uk = {
{ .decode = &decode_table },
{
[0x23] = 0x00a3,
}
};

View File

@@ -0,0 +1,111 @@
{ 0x1100, 0x115f },
{ 0x231a, 0x231b },
{ 0x2329, 0x232a },
{ 0x23e9, 0x23ec },
{ 0x23f0, 0x23f0 },
{ 0x23f3, 0x23f3 },
{ 0x25fd, 0x25fe },
{ 0x2614, 0x2615 },
{ 0x2648, 0x2653 },
{ 0x267f, 0x267f },
{ 0x2693, 0x2693 },
{ 0x26a1, 0x26a1 },
{ 0x26aa, 0x26ab },
{ 0x26bd, 0x26be },
{ 0x26c4, 0x26c5 },
{ 0x26ce, 0x26ce },
{ 0x26d4, 0x26d4 },
{ 0x26ea, 0x26ea },
{ 0x26f2, 0x26f3 },
{ 0x26f5, 0x26f5 },
{ 0x26fa, 0x26fa },
{ 0x26fd, 0x26fd },
{ 0x2705, 0x2705 },
{ 0x270a, 0x270b },
{ 0x2728, 0x2728 },
{ 0x274c, 0x274c },
{ 0x274e, 0x274e },
{ 0x2753, 0x2755 },
{ 0x2757, 0x2757 },
{ 0x2795, 0x2797 },
{ 0x27b0, 0x27b0 },
{ 0x27bf, 0x27bf },
{ 0x2b1b, 0x2b1c },
{ 0x2b50, 0x2b50 },
{ 0x2b55, 0x2b55 },
{ 0x2e80, 0x2e99 },
{ 0x2e9b, 0x2ef3 },
{ 0x2f00, 0x2fd5 },
{ 0x2ff0, 0x2ffb },
{ 0x3000, 0x303e },
{ 0x3041, 0x3096 },
{ 0x3099, 0x30ff },
{ 0x3105, 0x312f },
{ 0x3131, 0x318e },
{ 0x3190, 0x31ba },
{ 0x31c0, 0x31e3 },
{ 0x31f0, 0x321e },
{ 0x3220, 0x3247 },
{ 0x3250, 0x4dbf },
{ 0x4e00, 0xa48c },
{ 0xa490, 0xa4c6 },
{ 0xa960, 0xa97c },
{ 0xac00, 0xd7a3 },
{ 0xf900, 0xfaff },
{ 0xfe10, 0xfe19 },
{ 0xfe30, 0xfe52 },
{ 0xfe54, 0xfe66 },
{ 0xfe68, 0xfe6b },
{ 0xff01, 0xff60 },
{ 0xffe0, 0xffe6 },
{ 0x16fe0, 0x16fe3 },
{ 0x17000, 0x187f7 },
{ 0x18800, 0x18af2 },
{ 0x1b000, 0x1b11e },
{ 0x1b150, 0x1b152 },
{ 0x1b164, 0x1b167 },
{ 0x1b170, 0x1b2fb },
{ 0x1f004, 0x1f004 },
{ 0x1f0cf, 0x1f0cf },
{ 0x1f18e, 0x1f18e },
{ 0x1f191, 0x1f19a },
{ 0x1f200, 0x1f202 },
{ 0x1f210, 0x1f23b },
{ 0x1f240, 0x1f248 },
{ 0x1f250, 0x1f251 },
{ 0x1f260, 0x1f265 },
{ 0x1f300, 0x1f320 },
{ 0x1f32d, 0x1f335 },
{ 0x1f337, 0x1f37c },
{ 0x1f37e, 0x1f393 },
{ 0x1f3a0, 0x1f3ca },
{ 0x1f3cf, 0x1f3d3 },
{ 0x1f3e0, 0x1f3f0 },
{ 0x1f3f4, 0x1f3f4 },
{ 0x1f3f8, 0x1f43e },
{ 0x1f440, 0x1f440 },
{ 0x1f442, 0x1f4fc },
{ 0x1f4ff, 0x1f53d },
{ 0x1f54b, 0x1f54e },
{ 0x1f550, 0x1f567 },
{ 0x1f57a, 0x1f57a },
{ 0x1f595, 0x1f596 },
{ 0x1f5a4, 0x1f5a4 },
{ 0x1f5fb, 0x1f64f },
{ 0x1f680, 0x1f6c5 },
{ 0x1f6cc, 0x1f6cc },
{ 0x1f6d0, 0x1f6d2 },
{ 0x1f6d5, 0x1f6d5 },
{ 0x1f6eb, 0x1f6ec },
{ 0x1f6f4, 0x1f6fa },
{ 0x1f7e0, 0x1f7eb },
{ 0x1f90d, 0x1f971 },
{ 0x1f973, 0x1f976 },
{ 0x1f97a, 0x1f9a2 },
{ 0x1f9a5, 0x1f9aa },
{ 0x1f9ae, 0x1f9ca },
{ 0x1f9cd, 0x1f9ff },
{ 0x1fa70, 0x1fa73 },
{ 0x1fa78, 0x1fa7a },
{ 0x1fa80, 0x1fa82 },
{ 0x1fa90, 0x1fa95 },

View File

@@ -0,0 +1,226 @@
#include "vterm_internal.h"
#include <stdio.h>
#include "utf8.h"
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
{
/* The shift modifier is never important for Unicode characters
* apart from Space
*/
if(c != ' ')
mod &= ~VTERM_MOD_SHIFT;
if(mod == 0) {
// Normal text - ignore just shift
char str[6];
int seqlen = fill_utf8(c, str);
vterm_push_output_bytes(vt, str, seqlen);
return;
}
int needs_CSIu;
switch(c) {
/* Special Ctrl- letters that can't be represented elsewise */
case 'i': case 'j': case 'm': case '[':
needs_CSIu = 1;
break;
/* Ctrl-\ ] ^ _ don't need CSUu */
case '\\': case ']': case '^': case '_':
needs_CSIu = 0;
break;
/* Shift-space needs CSIu */
case ' ':
needs_CSIu = !!(mod & VTERM_MOD_SHIFT);
break;
/* All other characters needs CSIu except for letters a-z */
default:
needs_CSIu = (c < 'a' || c > 'z');
}
/* ALT we can just prefix with ESC; anything else requires CSI u */
if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) {
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1);
return;
}
if(mod & VTERM_MOD_CTRL)
c &= 0x1f;
vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? ESC_S : "", c);
}
typedef struct {
enum {
KEYCODE_NONE,
KEYCODE_LITERAL,
KEYCODE_TAB,
KEYCODE_ENTER,
KEYCODE_SS3,
KEYCODE_CSI,
KEYCODE_CSI_CURSOR,
KEYCODE_CSINUM,
KEYCODE_KEYPAD,
} type;
char literal;
int csinum;
} keycodes_s;
static keycodes_s keycodes[] = {
{ KEYCODE_NONE }, // NONE
{ KEYCODE_ENTER, '\r' }, // ENTER
{ KEYCODE_TAB, '\t' }, // TAB
{ KEYCODE_LITERAL, '\x7f' }, // BACKSPACE == ASCII DEL
{ KEYCODE_LITERAL, '\x1b' }, // ESCAPE
{ KEYCODE_CSI_CURSOR, 'A' }, // UP
{ KEYCODE_CSI_CURSOR, 'B' }, // DOWN
{ KEYCODE_CSI_CURSOR, 'D' }, // LEFT
{ KEYCODE_CSI_CURSOR, 'C' }, // RIGHT
{ KEYCODE_CSINUM, '~', 2 }, // INS
{ KEYCODE_CSINUM, '~', 3 }, // DEL
{ KEYCODE_CSI_CURSOR, 'H' }, // HOME
{ KEYCODE_CSI_CURSOR, 'F' }, // END
{ KEYCODE_CSINUM, '~', 5 }, // PAGEUP
{ KEYCODE_CSINUM, '~', 6 }, // PAGEDOWN
};
static keycodes_s keycodes_fn[] = {
{ KEYCODE_NONE }, // F0 - shouldn't happen
{ KEYCODE_SS3, 'P' }, // F1
{ KEYCODE_SS3, 'Q' }, // F2
{ KEYCODE_SS3, 'R' }, // F3
{ KEYCODE_SS3, 'S' }, // F4
{ KEYCODE_CSINUM, '~', 15 }, // F5
{ KEYCODE_CSINUM, '~', 17 }, // F6
{ KEYCODE_CSINUM, '~', 18 }, // F7
{ KEYCODE_CSINUM, '~', 19 }, // F8
{ KEYCODE_CSINUM, '~', 20 }, // F9
{ KEYCODE_CSINUM, '~', 21 }, // F10
{ KEYCODE_CSINUM, '~', 23 }, // F11
{ KEYCODE_CSINUM, '~', 24 }, // F12
};
static keycodes_s keycodes_kp[] = {
{ KEYCODE_KEYPAD, '0', 'p' }, // KP_0
{ KEYCODE_KEYPAD, '1', 'q' }, // KP_1
{ KEYCODE_KEYPAD, '2', 'r' }, // KP_2
{ KEYCODE_KEYPAD, '3', 's' }, // KP_3
{ KEYCODE_KEYPAD, '4', 't' }, // KP_4
{ KEYCODE_KEYPAD, '5', 'u' }, // KP_5
{ KEYCODE_KEYPAD, '6', 'v' }, // KP_6
{ KEYCODE_KEYPAD, '7', 'w' }, // KP_7
{ KEYCODE_KEYPAD, '8', 'x' }, // KP_8
{ KEYCODE_KEYPAD, '9', 'y' }, // KP_9
{ KEYCODE_KEYPAD, '*', 'j' }, // KP_MULT
{ KEYCODE_KEYPAD, '+', 'k' }, // KP_PLUS
{ KEYCODE_KEYPAD, ',', 'l' }, // KP_COMMA
{ KEYCODE_KEYPAD, '-', 'm' }, // KP_MINUS
{ KEYCODE_KEYPAD, '.', 'n' }, // KP_PERIOD
{ KEYCODE_KEYPAD, '/', 'o' }, // KP_DIVIDE
{ KEYCODE_KEYPAD, '\n', 'M' }, // KP_ENTER
{ KEYCODE_KEYPAD, '=', 'X' }, // KP_EQUAL
};
void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod)
{
if(key == VTERM_KEY_NONE)
return;
keycodes_s k;
if(key < VTERM_KEY_FUNCTION_0) {
if(key >= sizeof(keycodes)/sizeof(keycodes[0]))
return;
k = keycodes[key];
}
else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) {
if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0]))
return;
k = keycodes_fn[key - VTERM_KEY_FUNCTION_0];
}
else if(key >= VTERM_KEY_KP_0) {
if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0]))
return;
k = keycodes_kp[key - VTERM_KEY_KP_0];
}
switch(k.type) {
case KEYCODE_NONE:
break;
case KEYCODE_TAB:
/* Shift-Tab is CSI Z but plain Tab is 0x09 */
if(mod == VTERM_MOD_SHIFT)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z");
else if(mod & VTERM_MOD_SHIFT)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1);
else
goto case_LITERAL;
break;
case KEYCODE_ENTER:
/* Enter is CRLF in newline mode, but just LF in linefeed */
if(vt->state->mode.newline)
vterm_push_output_sprintf(vt, "\r\n");
else
goto case_LITERAL;
break;
case KEYCODE_LITERAL: case_LITERAL:
if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL))
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1);
else
vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal);
break;
case KEYCODE_SS3: case_SS3:
if(mod == 0)
vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal);
else
goto case_CSI;
break;
case KEYCODE_CSI: case_CSI:
if(mod == 0)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal);
else
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal);
break;
case KEYCODE_CSINUM:
if(mod == 0)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal);
else
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal);
break;
case KEYCODE_CSI_CURSOR:
if(vt->state->mode.cursor)
goto case_SS3;
else
goto case_CSI;
case KEYCODE_KEYPAD:
if(vt->state->mode.keypad) {
k.literal = k.csinum;
goto case_SS3;
}
else
goto case_LITERAL;
}
}
void vterm_keyboard_start_paste(VTerm *vt)
{
if(vt->state->mode.bracketpaste)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "200~");
}
void vterm_keyboard_end_paste(VTerm *vt)
{
if(vt->state->mode.bracketpaste)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "201~");
}

99
src/libs/3rdparty/libvterm/src/mouse.c vendored Normal file
View File

@@ -0,0 +1,99 @@
#include "vterm_internal.h"
#include "utf8.h"
static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row)
{
modifiers <<= 2;
switch(state->mouse_protocol) {
case MOUSE_X10:
if(col + 0x21 > 0xff)
col = 0xff - 0x21;
if(row + 0x21 > 0xff)
row = 0xff - 0x21;
if(!pressed)
code = 3;
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c",
(code | modifiers) + 0x20, col + 0x21, row + 0x21);
break;
case MOUSE_UTF8:
{
char utf8[18]; size_t len = 0;
if(!pressed)
code = 3;
len += fill_utf8((code | modifiers) + 0x20, utf8 + len);
len += fill_utf8(col + 0x21, utf8 + len);
len += fill_utf8(row + 0x21, utf8 + len);
utf8[len] = 0;
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8);
}
break;
case MOUSE_SGR:
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "<%d;%d;%d%c",
code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm');
break;
case MOUSE_RXVT:
if(!pressed)
code = 3;
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%d;%d;%dM",
code | modifiers, col + 1, row + 1);
break;
}
}
void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)
{
VTermState *state = vt->state;
if(col == state->mouse_col && row == state->mouse_row)
return;
state->mouse_col = col;
state->mouse_row = row;
if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) ||
(state->mouse_flags & MOUSE_WANT_MOVE)) {
int button = state->mouse_buttons & 0x01 ? 1 :
state->mouse_buttons & 0x02 ? 2 :
state->mouse_buttons & 0x04 ? 3 : 4;
output_mouse(state, button-1 + 0x20, 1, mod, col, row);
}
}
void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod)
{
VTermState *state = vt->state;
int old_buttons = state->mouse_buttons;
if(button > 0 && button <= 3) {
if(pressed)
state->mouse_buttons |= (1 << (button-1));
else
state->mouse_buttons &= ~(1 << (button-1));
}
/* Most of the time we don't get button releases from 4/5 */
if(state->mouse_buttons == old_buttons && button < 4)
return;
if(!state->mouse_flags)
return;
if(button < 4) {
output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row);
}
else if(button < 6) {
output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row);
}
}

402
src/libs/3rdparty/libvterm/src/parser.c vendored Normal file
View File

@@ -0,0 +1,402 @@
#include "vterm_internal.h"
#include <stdio.h>
#include <string.h>
#undef DEBUG_PARSER
static bool is_intermed(unsigned char c)
{
return c >= 0x20 && c <= 0x2f;
}
static void do_control(VTerm *vt, unsigned char control)
{
if(vt->parser.callbacks && vt->parser.callbacks->control)
if((*vt->parser.callbacks->control)(control, vt->parser.cbdata))
return;
DEBUG_LOG("libvterm: Unhandled control 0x%02x\n", control);
}
static void do_csi(VTerm *vt, char command)
{
#ifdef DEBUG_PARSER
printf("Parsed CSI args as:\n", arglen, args);
printf(" leader: %s\n", vt->parser.v.csi.leader);
for(int argi = 0; argi < vt->parser.v.csi.argi; argi++) {
printf(" %lu", CSI_ARG(vt->parser.v.csi.args[argi]));
if(!CSI_ARG_HAS_MORE(vt->parser.v.csi.args[argi]))
printf("\n");
printf(" intermed: %s\n", vt->parser.intermed);
}
#endif
if(vt->parser.callbacks && vt->parser.callbacks->csi)
if((*vt->parser.callbacks->csi)(
vt->parser.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL,
vt->parser.v.csi.args,
vt->parser.v.csi.argi,
vt->parser.intermedlen ? vt->parser.intermed : NULL,
command,
vt->parser.cbdata))
return;
DEBUG_LOG("libvterm: Unhandled CSI %c\n", command);
}
static void do_escape(VTerm *vt, char command)
{
char seq[INTERMED_MAX+1];
size_t len = vt->parser.intermedlen;
strncpy(seq, vt->parser.intermed, len);
seq[len++] = command;
seq[len] = 0;
if(vt->parser.callbacks && vt->parser.callbacks->escape)
if((*vt->parser.callbacks->escape)(seq, len, vt->parser.cbdata))
return;
DEBUG_LOG("libvterm: Unhandled escape ESC 0x%02x\n", command);
}
static void string_fragment(VTerm *vt, const char *str, size_t len, bool final)
{
VTermStringFragment frag = {
.str = str,
.len = len,
.initial = vt->parser.string_initial,
.final = final,
};
switch(vt->parser.state) {
case OSC:
if(vt->parser.callbacks && vt->parser.callbacks->osc)
(*vt->parser.callbacks->osc)(vt->parser.v.osc.command, frag, vt->parser.cbdata);
break;
case DCS:
if(vt->parser.callbacks && vt->parser.callbacks->dcs)
(*vt->parser.callbacks->dcs)(vt->parser.v.dcs.command, vt->parser.v.dcs.commandlen, frag, vt->parser.cbdata);
break;
case APC:
if(vt->parser.callbacks && vt->parser.callbacks->apc)
(*vt->parser.callbacks->apc)(frag, vt->parser.cbdata);
break;
case PM:
if(vt->parser.callbacks && vt->parser.callbacks->pm)
(*vt->parser.callbacks->pm)(frag, vt->parser.cbdata);
break;
case SOS:
if(vt->parser.callbacks && vt->parser.callbacks->sos)
(*vt->parser.callbacks->sos)(frag, vt->parser.cbdata);
break;
case NORMAL:
case CSI_LEADER:
case CSI_ARGS:
case CSI_INTERMED:
case OSC_COMMAND:
case DCS_COMMAND:
break;
}
vt->parser.string_initial = false;
}
size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
{
size_t pos = 0;
const char *string_start;
switch(vt->parser.state) {
case NORMAL:
case CSI_LEADER:
case CSI_ARGS:
case CSI_INTERMED:
case OSC_COMMAND:
case DCS_COMMAND:
string_start = NULL;
break;
case OSC:
case DCS:
case APC:
case PM:
case SOS:
string_start = bytes;
break;
}
#define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0)
#define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL)
#define IS_STRING_STATE() (vt->parser.state >= OSC_COMMAND)
for( ; pos < len; pos++) {
unsigned char c = bytes[pos];
bool c1_allowed = !vt->mode.utf8;
if(c == 0x00 || c == 0x7f) { // NUL, DEL
if(IS_STRING_STATE()) {
string_fragment(vt, string_start, bytes + pos - string_start, false);
string_start = bytes + pos + 1;
}
if(vt->parser.emit_nul)
do_control(vt, c);
continue;
}
if(c == 0x18 || c == 0x1a) { // CAN, SUB
vt->parser.in_esc = false;
ENTER_NORMAL_STATE();
if(vt->parser.emit_nul)
do_control(vt, c);
continue;
}
else if(c == 0x1b) { // ESC
vt->parser.intermedlen = 0;
if(!IS_STRING_STATE())
vt->parser.state = NORMAL;
vt->parser.in_esc = true;
continue;
}
else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state
IS_STRING_STATE()) {
// fallthrough
}
else if(c < 0x20) { // other C0
if(vt->parser.state == SOS)
continue; // All other C0s permitted in SOS
if(IS_STRING_STATE())
string_fragment(vt, string_start, bytes + pos - string_start, false);
do_control(vt, c);
if(IS_STRING_STATE())
string_start = bytes + pos + 1;
continue;
}
// else fallthrough
size_t string_len = bytes + pos - string_start;
if(vt->parser.in_esc) {
// Hoist an ESC letter into a C1 if we're not in a string mode
// Always accept ESC \ == ST even in string mode
if(!vt->parser.intermedlen &&
c >= 0x40 && c < 0x60 &&
((!IS_STRING_STATE() || c == 0x5c))) {
c += 0x40;
c1_allowed = true;
if(string_len)
string_len -= 1;
vt->parser.in_esc = false;
}
else {
string_start = NULL;
vt->parser.state = NORMAL;
}
}
switch(vt->parser.state) {
case CSI_LEADER:
/* Extract leader bytes 0x3c to 0x3f */
if(c >= 0x3c && c <= 0x3f) {
if(vt->parser.v.csi.leaderlen < CSI_LEADER_MAX-1)
vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c;
break;
}
/* else fallthrough */
vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0;
vt->parser.v.csi.argi = 0;
vt->parser.v.csi.args[0] = CSI_ARG_MISSING;
vt->parser.state = CSI_ARGS;
/* fallthrough */
case CSI_ARGS:
/* Numerical value of argument */
if(c >= '0' && c <= '9') {
if(vt->parser.v.csi.args[vt->parser.v.csi.argi] == CSI_ARG_MISSING)
vt->parser.v.csi.args[vt->parser.v.csi.argi] = 0;
vt->parser.v.csi.args[vt->parser.v.csi.argi] *= 10;
vt->parser.v.csi.args[vt->parser.v.csi.argi] += c - '0';
break;
}
if(c == ':') {
vt->parser.v.csi.args[vt->parser.v.csi.argi] |= CSI_ARG_FLAG_MORE;
c = ';';
}
if(c == ';') {
vt->parser.v.csi.argi++;
vt->parser.v.csi.args[vt->parser.v.csi.argi] = CSI_ARG_MISSING;
break;
}
/* else fallthrough */
vt->parser.v.csi.argi++;
vt->parser.intermedlen = 0;
vt->parser.state = CSI_INTERMED;
case CSI_INTERMED:
if(is_intermed(c)) {
if(vt->parser.intermedlen < INTERMED_MAX-1)
vt->parser.intermed[vt->parser.intermedlen++] = c;
break;
}
else if(c == 0x1b) {
/* ESC in CSI cancels */
}
else if(c >= 0x40 && c <= 0x7e) {
vt->parser.intermed[vt->parser.intermedlen] = 0;
do_csi(vt, c);
}
/* else was invalid CSI */
ENTER_NORMAL_STATE();
break;
case OSC_COMMAND:
/* Numerical value of command */
if(c >= '0' && c <= '9') {
if(vt->parser.v.osc.command == -1)
vt->parser.v.osc.command = 0;
else
vt->parser.v.osc.command *= 10;
vt->parser.v.osc.command += c - '0';
break;
}
if(c == ';') {
vt->parser.state = OSC;
string_start = bytes + pos + 1;
break;
}
/* else fallthrough */
string_start = bytes + pos;
string_len = 0;
vt->parser.state = OSC;
goto string_state;
case DCS_COMMAND:
if(vt->parser.v.dcs.commandlen < CSI_LEADER_MAX)
vt->parser.v.dcs.command[vt->parser.v.dcs.commandlen++] = c;
if(c >= 0x40 && c<= 0x7e) {
string_start = bytes + pos + 1;
vt->parser.state = DCS;
}
break;
string_state:
case OSC:
case DCS:
case APC:
case PM:
case SOS:
if(c == 0x07 || (c1_allowed && c == 0x9c)) {
string_fragment(vt, string_start, string_len, true);
ENTER_NORMAL_STATE();
}
break;
case NORMAL:
if(vt->parser.in_esc) {
if(is_intermed(c)) {
if(vt->parser.intermedlen < INTERMED_MAX-1)
vt->parser.intermed[vt->parser.intermedlen++] = c;
}
else if(c >= 0x30 && c < 0x7f) {
do_escape(vt, c);
vt->parser.in_esc = 0;
ENTER_NORMAL_STATE();
}
else {
DEBUG_LOG("TODO: Unhandled byte %02x in Escape\n", c);
}
break;
}
if(c1_allowed && c >= 0x80 && c < 0xa0) {
switch(c) {
case 0x90: // DCS
vt->parser.string_initial = true;
vt->parser.v.dcs.commandlen = 0;
ENTER_STATE(DCS_COMMAND);
break;
case 0x98: // SOS
vt->parser.string_initial = true;
ENTER_STATE(SOS);
string_start = bytes + pos + 1;
string_len = 0;
break;
case 0x9b: // CSI
vt->parser.v.csi.leaderlen = 0;
ENTER_STATE(CSI_LEADER);
break;
case 0x9d: // OSC
vt->parser.v.osc.command = -1;
vt->parser.string_initial = true;
string_start = bytes + pos + 1;
ENTER_STATE(OSC_COMMAND);
break;
case 0x9e: // PM
vt->parser.string_initial = true;
ENTER_STATE(PM);
string_start = bytes + pos + 1;
string_len = 0;
break;
case 0x9f: // APC
vt->parser.string_initial = true;
ENTER_STATE(APC);
string_start = bytes + pos + 1;
string_len = 0;
break;
default:
do_control(vt, c);
break;
}
}
else {
size_t eaten = 0;
if(vt->parser.callbacks && vt->parser.callbacks->text)
eaten = (*vt->parser.callbacks->text)(bytes + pos, len - pos, vt->parser.cbdata);
if(!eaten) {
DEBUG_LOG("libvterm: Text callback did not consume any input\n");
/* force it to make progress */
eaten = 1;
}
pos += (eaten - 1); // we'll ++ it again in a moment
}
break;
}
}
if(string_start) {
size_t string_len = bytes + pos - string_start;
if(vt->parser.in_esc)
string_len -= 1;
string_fragment(vt, string_start, string_len, false);
}
return len;
}
void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)
{
vt->parser.callbacks = callbacks;
vt->parser.cbdata = user;
}
void *vterm_parser_get_cbdata(VTerm *vt)
{
return vt->parser.cbdata;
}
void vterm_parser_set_emit_nul(VTerm *vt, bool emit)
{
vt->parser.emit_nul = emit;
}

607
src/libs/3rdparty/libvterm/src/pen.c vendored Normal file
View File

@@ -0,0 +1,607 @@
#include "vterm_internal.h"
#include <stdio.h>
/**
* Structure used to store RGB triples without the additional metadata stored in
* VTermColor.
*/
typedef struct {
uint8_t red, green, blue;
} VTermRGB;
static const VTermRGB ansi_colors[] = {
/* R G B */
{ 0, 0, 0 }, // black
{ 224, 0, 0 }, // red
{ 0, 224, 0 }, // green
{ 224, 224, 0 }, // yellow
{ 0, 0, 224 }, // blue
{ 224, 0, 224 }, // magenta
{ 0, 224, 224 }, // cyan
{ 224, 224, 224 }, // white == light grey
// high intensity
{ 128, 128, 128 }, // black
{ 255, 64, 64 }, // red
{ 64, 255, 64 }, // green
{ 255, 255, 64 }, // yellow
{ 64, 64, 255 }, // blue
{ 255, 64, 255 }, // magenta
{ 64, 255, 255 }, // cyan
{ 255, 255, 255 }, // white for real
};
static int ramp6[] = {
0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF,
};
static int ramp24[] = {
0x00, 0x0B, 0x16, 0x21, 0x2C, 0x37, 0x42, 0x4D, 0x58, 0x63, 0x6E, 0x79,
0x85, 0x90, 0x9B, 0xA6, 0xB1, 0xBC, 0xC7, 0xD2, 0xDD, 0xE8, 0xF3, 0xFF,
};
static void lookup_default_colour_ansi(long idx, VTermColor *col)
{
if (idx >= 0 && idx < 16) {
vterm_color_rgb(
col,
ansi_colors[idx].red, ansi_colors[idx].green, ansi_colors[idx].blue);
}
}
static bool lookup_colour_ansi(const VTermState *state, long index, VTermColor *col)
{
if(index >= 0 && index < 16) {
*col = state->colors[index];
return true;
}
return false;
}
static bool lookup_colour_palette(const VTermState *state, long index, VTermColor *col)
{
if(index >= 0 && index < 16) {
// Normal 8 colours or high intensity - parse as palette 0
return lookup_colour_ansi(state, index, col);
}
else if(index >= 16 && index < 232) {
// 216-colour cube
index -= 16;
vterm_color_rgb(col, ramp6[index/6/6 % 6],
ramp6[index/6 % 6],
ramp6[index % 6]);
return true;
}
else if(index >= 232 && index < 256) {
// 24 greyscales
index -= 232;
vterm_color_rgb(col, ramp24[index], ramp24[index], ramp24[index]);
return true;
}
return false;
}
static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col)
{
switch(palette) {
case 2: // RGB mode - 3 args contain colour values directly
if(argcount < 3)
return argcount;
vterm_color_rgb(col, CSI_ARG(args[0]), CSI_ARG(args[1]), CSI_ARG(args[2]));
return 3;
case 5: // XTerm 256-colour mode
if (!argcount || CSI_ARG_IS_MISSING(args[0])) {
return argcount ? 1 : 0;
}
vterm_color_indexed(col, args[0]);
return argcount ? 1 : 0;
default:
DEBUG_LOG("Unrecognised colour palette %d\n", palette);
return 0;
}
}
// Some conveniences
static void setpenattr(VTermState *state, VTermAttr attr, VTermValueType type, VTermValue *val)
{
#ifdef DEBUG
if(type != vterm_get_attr_type(attr)) {
DEBUG_LOG("Cannot set attr %d as it has type %d, not type %d\n",
attr, vterm_get_attr_type(attr), type);
return;
}
#endif
if(state->callbacks && state->callbacks->setpenattr)
(*state->callbacks->setpenattr)(attr, val, state->cbdata);
}
static void setpenattr_bool(VTermState *state, VTermAttr attr, int boolean)
{
VTermValue val = { .boolean = boolean };
setpenattr(state, attr, VTERM_VALUETYPE_BOOL, &val);
}
static void setpenattr_int(VTermState *state, VTermAttr attr, int number)
{
VTermValue val = { .number = number };
setpenattr(state, attr, VTERM_VALUETYPE_INT, &val);
}
static void setpenattr_col(VTermState *state, VTermAttr attr, VTermColor color)
{
VTermValue val = { .color = color };
setpenattr(state, attr, VTERM_VALUETYPE_COLOR, &val);
}
static void set_pen_col_ansi(VTermState *state, VTermAttr attr, long col)
{
VTermColor *colp = (attr == VTERM_ATTR_BACKGROUND) ? &state->pen.bg : &state->pen.fg;
vterm_color_indexed(colp, col);
setpenattr_col(state, attr, *colp);
}
INTERNAL void vterm_state_newpen(VTermState *state)
{
// 90% grey so that pure white is brighter
vterm_color_rgb(&state->default_fg, 240, 240, 240);
vterm_color_rgb(&state->default_bg, 0, 0, 0);
vterm_state_set_default_colors(state, &state->default_fg, &state->default_bg);
for(int col = 0; col < 16; col++)
lookup_default_colour_ansi(col, &state->colors[col]);
}
INTERNAL void vterm_state_resetpen(VTermState *state)
{
state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0);
state->pen.underline = 0; setpenattr_int (state, VTERM_ATTR_UNDERLINE, 0);
state->pen.italic = 0; setpenattr_bool(state, VTERM_ATTR_ITALIC, 0);
state->pen.blink = 0; setpenattr_bool(state, VTERM_ATTR_BLINK, 0);
state->pen.reverse = 0; setpenattr_bool(state, VTERM_ATTR_REVERSE, 0);
state->pen.conceal = 0; setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0);
state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0);
state->pen.font = 0; setpenattr_int (state, VTERM_ATTR_FONT, 0);
state->pen.small = 0; setpenattr_bool(state, VTERM_ATTR_SMALL, 0);
state->pen.baseline = 0; setpenattr_int (state, VTERM_ATTR_BASELINE, 0);
state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg);
state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg);
}
INTERNAL void vterm_state_savepen(VTermState *state, int save)
{
if(save) {
state->saved.pen = state->pen;
}
else {
state->pen = state->saved.pen;
setpenattr_bool(state, VTERM_ATTR_BOLD, state->pen.bold);
setpenattr_int (state, VTERM_ATTR_UNDERLINE, state->pen.underline);
setpenattr_bool(state, VTERM_ATTR_ITALIC, state->pen.italic);
setpenattr_bool(state, VTERM_ATTR_BLINK, state->pen.blink);
setpenattr_bool(state, VTERM_ATTR_REVERSE, state->pen.reverse);
setpenattr_bool(state, VTERM_ATTR_CONCEAL, state->pen.conceal);
setpenattr_bool(state, VTERM_ATTR_STRIKE, state->pen.strike);
setpenattr_int (state, VTERM_ATTR_FONT, state->pen.font);
setpenattr_bool(state, VTERM_ATTR_SMALL, state->pen.small);
setpenattr_int (state, VTERM_ATTR_BASELINE, state->pen.baseline);
setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg);
setpenattr_col( state, VTERM_ATTR_BACKGROUND, state->pen.bg);
}
}
int vterm_color_is_equal(const VTermColor *a, const VTermColor *b)
{
/* First make sure that the two colours are of the same type (RGB/Indexed) */
if (a->type != b->type) {
return false;
}
/* Depending on the type inspect the corresponding members */
if (VTERM_COLOR_IS_INDEXED(a)) {
return a->indexed.idx == b->indexed.idx;
}
else if (VTERM_COLOR_IS_RGB(a)) {
return (a->rgb.red == b->rgb.red)
&& (a->rgb.green == b->rgb.green)
&& (a->rgb.blue == b->rgb.blue);
}
return 0;
}
void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg)
{
*default_fg = state->default_fg;
*default_bg = state->default_bg;
}
void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col)
{
lookup_colour_palette(state, index, col);
}
void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg)
{
if(default_fg) {
state->default_fg = *default_fg;
state->default_fg.type = (state->default_fg.type & ~VTERM_COLOR_DEFAULT_MASK)
| VTERM_COLOR_DEFAULT_FG;
}
if(default_bg) {
state->default_bg = *default_bg;
state->default_bg.type = (state->default_bg.type & ~VTERM_COLOR_DEFAULT_MASK)
| VTERM_COLOR_DEFAULT_BG;
}
}
void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col)
{
if(index >= 0 && index < 16)
state->colors[index] = *col;
}
void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col)
{
if (VTERM_COLOR_IS_INDEXED(col)) { /* Convert indexed colors to RGB */
lookup_colour_palette(state, col->indexed.idx, col);
}
col->type &= VTERM_COLOR_TYPE_MASK; /* Reset any metadata but the type */
}
void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright)
{
state->bold_is_highbright = bold_is_highbright;
}
INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argcount)
{
// SGR - ECMA-48 8.3.117
int argi = 0;
int value;
while(argi < argcount) {
// This logic is easier to do 'done' backwards; set it true, and make it
// false again in the 'default' case
int done = 1;
long arg;
switch(arg = CSI_ARG(args[argi])) {
case CSI_ARG_MISSING:
case 0: // Reset
vterm_state_resetpen(state);
break;
case 1: { // Bold on
const VTermColor *fg = &state->pen.fg;
state->pen.bold = 1;
setpenattr_bool(state, VTERM_ATTR_BOLD, 1);
if(!VTERM_COLOR_IS_DEFAULT_FG(fg) && VTERM_COLOR_IS_INDEXED(fg) && fg->indexed.idx < 8 && state->bold_is_highbright)
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, fg->indexed.idx + (state->pen.bold ? 8 : 0));
break;
}
case 3: // Italic on
state->pen.italic = 1;
setpenattr_bool(state, VTERM_ATTR_ITALIC, 1);
break;
case 4: // Underline
state->pen.underline = VTERM_UNDERLINE_SINGLE;
if(CSI_ARG_HAS_MORE(args[argi])) {
argi++;
switch(CSI_ARG(args[argi])) {
case 0:
state->pen.underline = 0;
break;
case 1:
state->pen.underline = VTERM_UNDERLINE_SINGLE;
break;
case 2:
state->pen.underline = VTERM_UNDERLINE_DOUBLE;
break;
case 3:
state->pen.underline = VTERM_UNDERLINE_CURLY;
break;
}
}
setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline);
break;
case 5: // Blink
state->pen.blink = 1;
setpenattr_bool(state, VTERM_ATTR_BLINK, 1);
break;
case 7: // Reverse on
state->pen.reverse = 1;
setpenattr_bool(state, VTERM_ATTR_REVERSE, 1);
break;
case 8: // Conceal on
state->pen.conceal = 1;
setpenattr_bool(state, VTERM_ATTR_CONCEAL, 1);
break;
case 9: // Strikethrough on
state->pen.strike = 1;
setpenattr_bool(state, VTERM_ATTR_STRIKE, 1);
break;
case 10: case 11: case 12: case 13: case 14:
case 15: case 16: case 17: case 18: case 19: // Select font
state->pen.font = CSI_ARG(args[argi]) - 10;
setpenattr_int(state, VTERM_ATTR_FONT, state->pen.font);
break;
case 21: // Underline double
state->pen.underline = VTERM_UNDERLINE_DOUBLE;
setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline);
break;
case 22: // Bold off
state->pen.bold = 0;
setpenattr_bool(state, VTERM_ATTR_BOLD, 0);
break;
case 23: // Italic and Gothic (currently unsupported) off
state->pen.italic = 0;
setpenattr_bool(state, VTERM_ATTR_ITALIC, 0);
break;
case 24: // Underline off
state->pen.underline = 0;
setpenattr_int(state, VTERM_ATTR_UNDERLINE, 0);
break;
case 25: // Blink off
state->pen.blink = 0;
setpenattr_bool(state, VTERM_ATTR_BLINK, 0);
break;
case 27: // Reverse off
state->pen.reverse = 0;
setpenattr_bool(state, VTERM_ATTR_REVERSE, 0);
break;
case 28: // Conceal off (Reveal)
state->pen.conceal = 0;
setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0);
break;
case 29: // Strikethrough off
state->pen.strike = 0;
setpenattr_bool(state, VTERM_ATTR_STRIKE, 0);
break;
case 30: case 31: case 32: case 33:
case 34: case 35: case 36: case 37: // Foreground colour palette
value = CSI_ARG(args[argi]) - 30;
if(state->pen.bold && state->bold_is_highbright)
value += 8;
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);
break;
case 38: // Foreground colour alternative palette
if(argcount - argi < 1)
return;
argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg);
setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);
break;
case 39: // Foreground colour default
state->pen.fg = state->default_fg;
setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);
break;
case 40: case 41: case 42: case 43:
case 44: case 45: case 46: case 47: // Background colour palette
value = CSI_ARG(args[argi]) - 40;
set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);
break;
case 48: // Background colour alternative palette
if(argcount - argi < 1)
return;
argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg);
setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);
break;
case 49: // Default background
state->pen.bg = state->default_bg;
setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);
break;
case 73: // Superscript
case 74: // Subscript
case 75: // Superscript/subscript off
state->pen.small = (arg != 75);
state->pen.baseline =
(arg == 73) ? VTERM_BASELINE_RAISE :
(arg == 74) ? VTERM_BASELINE_LOWER :
VTERM_BASELINE_NORMAL;
setpenattr_bool(state, VTERM_ATTR_SMALL, state->pen.small);
setpenattr_int (state, VTERM_ATTR_BASELINE, state->pen.baseline);
break;
case 90: case 91: case 92: case 93:
case 94: case 95: case 96: case 97: // Foreground colour high-intensity palette
value = CSI_ARG(args[argi]) - 90 + 8;
set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);
break;
case 100: case 101: case 102: case 103:
case 104: case 105: case 106: case 107: // Background colour high-intensity palette
value = CSI_ARG(args[argi]) - 100 + 8;
set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);
break;
default:
done = 0;
break;
}
if(!done)
DEBUG_LOG("libvterm: Unhandled CSI SGR %ld\n", arg);
while(CSI_ARG_HAS_MORE(args[argi++]));
}
}
static int vterm_state_getpen_color(const VTermColor *col, int argi, long args[], int fg)
{
/* Do nothing if the given color is the default color */
if (( fg && VTERM_COLOR_IS_DEFAULT_FG(col)) ||
(!fg && VTERM_COLOR_IS_DEFAULT_BG(col))) {
return argi;
}
/* Decide whether to send an indexed color or an RGB color */
if (VTERM_COLOR_IS_INDEXED(col)) {
const uint8_t idx = col->indexed.idx;
if (idx < 8) {
args[argi++] = (idx + (fg ? 30 : 40));
}
else if (idx < 16) {
args[argi++] = (idx - 8 + (fg ? 90 : 100));
}
else {
args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48);
args[argi++] = CSI_ARG_FLAG_MORE | 5;
args[argi++] = idx;
}
}
else if (VTERM_COLOR_IS_RGB(col)) {
args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48);
args[argi++] = CSI_ARG_FLAG_MORE | 2;
args[argi++] = CSI_ARG_FLAG_MORE | col->rgb.red;
args[argi++] = CSI_ARG_FLAG_MORE | col->rgb.green;
args[argi++] = col->rgb.blue;
}
return argi;
}
INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount)
{
int argi = 0;
if(state->pen.bold)
args[argi++] = 1;
if(state->pen.italic)
args[argi++] = 3;
if(state->pen.underline == VTERM_UNDERLINE_SINGLE)
args[argi++] = 4;
if(state->pen.underline == VTERM_UNDERLINE_CURLY)
args[argi++] = 4 | CSI_ARG_FLAG_MORE, args[argi++] = 3;
if(state->pen.blink)
args[argi++] = 5;
if(state->pen.reverse)
args[argi++] = 7;
if(state->pen.conceal)
args[argi++] = 8;
if(state->pen.strike)
args[argi++] = 9;
if(state->pen.font)
args[argi++] = 10 + state->pen.font;
if(state->pen.underline == VTERM_UNDERLINE_DOUBLE)
args[argi++] = 21;
argi = vterm_state_getpen_color(&state->pen.fg, argi, args, true);
argi = vterm_state_getpen_color(&state->pen.bg, argi, args, false);
if(state->pen.small) {
if(state->pen.baseline == VTERM_BASELINE_RAISE)
args[argi++] = 73;
else if(state->pen.baseline == VTERM_BASELINE_LOWER)
args[argi++] = 74;
}
return argi;
}
int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val)
{
switch(attr) {
case VTERM_ATTR_BOLD:
val->boolean = state->pen.bold;
return 1;
case VTERM_ATTR_UNDERLINE:
val->number = state->pen.underline;
return 1;
case VTERM_ATTR_ITALIC:
val->boolean = state->pen.italic;
return 1;
case VTERM_ATTR_BLINK:
val->boolean = state->pen.blink;
return 1;
case VTERM_ATTR_REVERSE:
val->boolean = state->pen.reverse;
return 1;
case VTERM_ATTR_CONCEAL:
val->boolean = state->pen.conceal;
return 1;
case VTERM_ATTR_STRIKE:
val->boolean = state->pen.strike;
return 1;
case VTERM_ATTR_FONT:
val->number = state->pen.font;
return 1;
case VTERM_ATTR_FOREGROUND:
val->color = state->pen.fg;
return 1;
case VTERM_ATTR_BACKGROUND:
val->color = state->pen.bg;
return 1;
case VTERM_ATTR_SMALL:
val->boolean = state->pen.small;
return 1;
case VTERM_ATTR_BASELINE:
val->number = state->pen.baseline;
return 1;
case VTERM_N_ATTRS:
return 0;
}
return 0;
}

56
src/libs/3rdparty/libvterm/src/rect.h vendored Normal file
View File

@@ -0,0 +1,56 @@
/*
* Some utility functions on VTermRect structures
*/
#define STRFrect "(%d,%d-%d,%d)"
#define ARGSrect(r) (r).start_row, (r).start_col, (r).end_row, (r).end_col
/* Expand dst to contain src as well */
static void rect_expand(VTermRect *dst, VTermRect *src)
{
if(dst->start_row > src->start_row) dst->start_row = src->start_row;
if(dst->start_col > src->start_col) dst->start_col = src->start_col;
if(dst->end_row < src->end_row) dst->end_row = src->end_row;
if(dst->end_col < src->end_col) dst->end_col = src->end_col;
}
/* Clip the dst to ensure it does not step outside of bounds */
static void rect_clip(VTermRect *dst, VTermRect *bounds)
{
if(dst->start_row < bounds->start_row) dst->start_row = bounds->start_row;
if(dst->start_col < bounds->start_col) dst->start_col = bounds->start_col;
if(dst->end_row > bounds->end_row) dst->end_row = bounds->end_row;
if(dst->end_col > bounds->end_col) dst->end_col = bounds->end_col;
/* Ensure it doesn't end up negatively-sized */
if(dst->end_row < dst->start_row) dst->end_row = dst->start_row;
if(dst->end_col < dst->start_col) dst->end_col = dst->start_col;
}
/* True if the two rectangles are equal */
static int rect_equal(VTermRect *a, VTermRect *b)
{
return (a->start_row == b->start_row) &&
(a->start_col == b->start_col) &&
(a->end_row == b->end_row) &&
(a->end_col == b->end_col);
}
/* True if small is contained entirely within big */
static int rect_contains(VTermRect *big, VTermRect *small)
{
if(small->start_row < big->start_row) return 0;
if(small->start_col < big->start_col) return 0;
if(small->end_row > big->end_row) return 0;
if(small->end_col > big->end_col) return 0;
return 1;
}
/* True if the rectangles overlap at all */
static int rect_intersects(VTermRect *a, VTermRect *b)
{
if(a->start_row > b->end_row || b->start_row > a->end_row)
return 0;
if(a->start_col > b->end_col || b->start_col > a->end_col)
return 0;
return 1;
}

1183
src/libs/3rdparty/libvterm/src/screen.c vendored Normal file

File diff suppressed because it is too large Load Diff

2315
src/libs/3rdparty/libvterm/src/state.c vendored Normal file

File diff suppressed because it is too large Load Diff

313
src/libs/3rdparty/libvterm/src/unicode.c vendored Normal file
View File

@@ -0,0 +1,313 @@
#include "vterm_internal.h"
// ### The following from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
// With modifications:
// made functions static
// moved 'combining' table to file scope, so other functions can see it
// ###################################################################
/*
* This is an implementation of wcwidth() and wcswidth() (defined in
* IEEE Std 1002.1-2001) for Unicode.
*
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
*
* In fixed-width output devices, Latin characters all occupy a single
* "cell" position of equal width, whereas ideographic CJK characters
* occupy two such cells. Interoperability between terminal-line
* applications and (teletype-style) character terminals using the
* UTF-8 encoding requires agreement on which character should advance
* the cursor by how many cell positions. No established formal
* standards exist at present on which Unicode character shall occupy
* how many cell positions on character terminals. These routines are
* a first attempt of defining such behavior based on simple rules
* applied to data provided by the Unicode Consortium.
*
* For some graphical characters, the Unicode standard explicitly
* defines a character-cell width via the definition of the East Asian
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
* In all these cases, there is no ambiguity about which width a
* terminal shall use. For characters in the East Asian Ambiguous (A)
* class, the width choice depends purely on a preference of backward
* compatibility with either historic CJK or Western practice.
* Choosing single-width for these characters is easy to justify as
* the appropriate long-term solution, as the CJK practice of
* displaying these characters as double-width comes from historic
* implementation simplicity (8-bit encoded characters were displayed
* single-width and 16-bit ones double-width, even for Greek,
* Cyrillic, etc.) and not any typographic considerations.
*
* Much less clear is the choice of width for the Not East Asian
* (Neutral) class. Existing practice does not dictate a width for any
* of these characters. It would nevertheless make sense
* typographically to allocate two character cells to characters such
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
* represented adequately with a single-width glyph. The following
* routines at present merely assign a single-cell width to all
* neutral characters, in the interest of simplicity. This is not
* entirely satisfactory and should be reconsidered before
* establishing a formal standard in this area. At the moment, the
* decision which Not East Asian (Neutral) characters should be
* represented by double-width glyphs cannot yet be answered by
* applying a simple rule from the Unicode database content. Setting
* up a proper standard for the behavior of UTF-8 character terminals
* will require a careful analysis not only of each Unicode character,
* but also of each presentation form, something the author of these
* routines has avoided to do so far.
*
* http://www.unicode.org/unicode/reports/tr11/
*
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
*
* Permission to use, copy, modify, and distribute this software
* for any purpose and without fee is hereby granted. The author
* disclaims all warranties with regard to this software.
*
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
struct interval {
int first;
int last;
};
/* sorted list of non-overlapping intervals of non-spacing characters */
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
static const struct interval combining[] = {
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
{ 0xE0100, 0xE01EF }
};
/* auxiliary function for binary search in interval table */
static int bisearch(uint32_t ucs, const struct interval *table, int max) {
int min = 0;
int mid;
if (ucs < table[0].first || ucs > table[max].last)
return 0;
while (max >= min) {
mid = (min + max) / 2;
if (ucs > table[mid].last)
min = mid + 1;
else if (ucs < table[mid].first)
max = mid - 1;
else
return 1;
}
return 0;
}
/* The following two functions define the column width of an ISO 10646
* character as follows:
*
* - The null character (U+0000) has a column width of 0.
*
* - Other C0/C1 control characters and DEL will lead to a return
* value of -1.
*
* - Non-spacing and enclosing combining characters (general
* category code Mn or Me in the Unicode database) have a
* column width of 0.
*
* - SOFT HYPHEN (U+00AD) has a column width of 1.
*
* - Other format characters (general category code Cf in the Unicode
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
*
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
* have a column width of 0.
*
* - Spacing characters in the East Asian Wide (W) or East Asian
* Full-width (F) category as defined in Unicode Technical
* Report #11 have a column width of 2.
*
* - All remaining characters (including all printable
* ISO 8859-1 and WGL4 characters, Unicode control characters,
* etc.) have a column width of 1.
*
* This implementation assumes that uint32_t characters are encoded
* in ISO 10646.
*/
static int mk_wcwidth(uint32_t ucs)
{
/* test for 8-bit control characters */
if (ucs == 0)
return 0;
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
return -1;
/* binary search in table of non-spacing characters */
if (bisearch(ucs, combining,
sizeof(combining) / sizeof(struct interval) - 1))
return 0;
/* if we arrive here, ucs is not a combining or C0/C1 control character */
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
ucs == 0x2329 || ucs == 0x232a ||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
(ucs >= 0x30000 && ucs <= 0x3fffd)));
}
#ifdef USE_MK_WCWIDTH_CJK
/*
* The following functions are the same as mk_wcwidth() and
* mk_wcswidth(), except that spacing characters in the East Asian
* Ambiguous (A) category as defined in Unicode Technical Report #11
* have a column width of 2. This variant might be useful for users of
* CJK legacy encodings who want to migrate to UCS without changing
* the traditional terminal character-width behaviour. It is not
* otherwise recommended for general use.
*/
static int mk_wcwidth_cjk(uint32_t ucs)
{
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
static const struct interval ambiguous[] = {
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
{ 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
{ 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
{ 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
{ 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
{ 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
{ 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
{ 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
{ 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
{ 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
{ 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
{ 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
{ 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
{ 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
{ 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
{ 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
{ 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
{ 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
{ 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
{ 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
{ 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
{ 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
{ 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
{ 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
{ 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
{ 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
{ 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
{ 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
{ 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
{ 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
{ 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
{ 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
{ 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
{ 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
{ 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
{ 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
{ 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
{ 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
};
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1))
return 2;
return mk_wcwidth(ucs);
}
#endif
// ################################
// ### The rest added by Paul Evans
static const struct interval fullwidth[] = {
#include "fullwidth.inc"
};
INTERNAL int vterm_unicode_width(uint32_t codepoint)
{
if(bisearch(codepoint, fullwidth, sizeof(fullwidth) / sizeof(fullwidth[0]) - 1))
return 2;
return mk_wcwidth(codepoint);
}
INTERNAL int vterm_unicode_is_combining(uint32_t codepoint)
{
return bisearch(codepoint, combining, sizeof(combining) / sizeof(struct interval) - 1);
}

39
src/libs/3rdparty/libvterm/src/utf8.h vendored Normal file
View File

@@ -0,0 +1,39 @@
/* The following functions copied and adapted from libtermkey
*
* http://www.leonerd.org.uk/code/libtermkey/
*/
static inline unsigned int utf8_seqlen(long codepoint)
{
if(codepoint < 0x0000080) return 1;
if(codepoint < 0x0000800) return 2;
if(codepoint < 0x0010000) return 3;
if(codepoint < 0x0200000) return 4;
if(codepoint < 0x4000000) return 5;
return 6;
}
/* Does NOT NUL-terminate the buffer */
static int fill_utf8(long codepoint, char *str)
{
int nbytes = utf8_seqlen(codepoint);
// This is easier done backwards
int b = nbytes;
while(b > 1) {
b--;
str[b] = 0x80 | (codepoint & 0x3f);
codepoint >>= 6;
}
switch(nbytes) {
case 1: str[0] = (codepoint & 0x7f); break;
case 2: str[0] = 0xc0 | (codepoint & 0x1f); break;
case 3: str[0] = 0xe0 | (codepoint & 0x0f); break;
case 4: str[0] = 0xf0 | (codepoint & 0x07); break;
case 5: str[0] = 0xf8 | (codepoint & 0x03); break;
case 6: str[0] = 0xfc | (codepoint & 0x01); break;
}
return nbytes;
}
/* end copy */

429
src/libs/3rdparty/libvterm/src/vterm.c vendored Normal file
View File

@@ -0,0 +1,429 @@
#include "vterm_internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
/*****************
* API functions *
*****************/
static void *default_malloc(size_t size, void *allocdata)
{
void *ptr = malloc(size);
if(ptr)
memset(ptr, 0, size);
return ptr;
}
static void default_free(void *ptr, void *allocdata)
{
free(ptr);
}
static VTermAllocatorFunctions default_allocator = {
.malloc = &default_malloc,
.free = &default_free,
};
VTerm *vterm_new(int rows, int cols)
{
return vterm_build(&(const struct VTermBuilder){
.rows = rows,
.cols = cols,
});
}
VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata)
{
return vterm_build(&(const struct VTermBuilder){
.rows = rows,
.cols = cols,
.allocator = funcs,
.allocdata = allocdata,
});
}
/* A handy macro for defaulting values out of builder fields */
#define DEFAULT(v, def) ((v) ? (v) : (def))
VTerm *vterm_build(const struct VTermBuilder *builder)
{
const VTermAllocatorFunctions *allocator = DEFAULT(builder->allocator, &default_allocator);
/* Need to bootstrap using the allocator function directly */
VTerm *vt = (*allocator->malloc)(sizeof(VTerm), builder->allocdata);
vt->allocator = allocator;
vt->allocdata = builder->allocdata;
vt->rows = builder->rows;
vt->cols = builder->cols;
vt->parser.state = NORMAL;
vt->parser.callbacks = NULL;
vt->parser.cbdata = NULL;
vt->parser.emit_nul = false;
vt->outfunc = NULL;
vt->outdata = NULL;
vt->outbuffer_len = DEFAULT(builder->outbuffer_len, 4096);
vt->outbuffer_cur = 0;
vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);
vt->tmpbuffer_len = DEFAULT(builder->tmpbuffer_len, 4096);
vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len);
return vt;
}
void vterm_free(VTerm *vt)
{
if(vt->screen)
vterm_screen_free(vt->screen);
if(vt->state)
vterm_state_free(vt->state);
vterm_allocator_free(vt, vt->outbuffer);
vterm_allocator_free(vt, vt->tmpbuffer);
vterm_allocator_free(vt, vt);
}
INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
{
return (*vt->allocator->malloc)(size, vt->allocdata);
}
INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
{
(*vt->allocator->free)(ptr, vt->allocdata);
}
void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
{
if(rowsp)
*rowsp = vt->rows;
if(colsp)
*colsp = vt->cols;
}
void vterm_set_size(VTerm *vt, int rows, int cols)
{
if(rows < 1 || cols < 1)
return;
vt->rows = rows;
vt->cols = cols;
if(vt->parser.callbacks && vt->parser.callbacks->resize)
(*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata);
}
int vterm_get_utf8(const VTerm *vt)
{
return vt->mode.utf8;
}
void vterm_set_utf8(VTerm *vt, int is_utf8)
{
vt->mode.utf8 = is_utf8;
}
void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user)
{
vt->outfunc = func;
vt->outdata = user;
}
INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
{
if(vt->outfunc) {
(vt->outfunc)(bytes, len, vt->outdata);
return;
}
if(len > vt->outbuffer_len - vt->outbuffer_cur)
return;
memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len);
vt->outbuffer_cur += len;
}
INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
{
size_t len = vsnprintf(vt->tmpbuffer, vt->tmpbuffer_len,
format, args);
vterm_push_output_bytes(vt, vt->tmpbuffer, len);
}
INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
{
va_list args;
va_start(args, format);
vterm_push_output_vsprintf(vt, format, args);
va_end(args);
}
INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
{
size_t cur;
if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
ESC_S "%c", ctrl - 0x40);
else
cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
"%c", ctrl);
if(cur >= vt->tmpbuffer_len)
return;
va_list args;
va_start(args, fmt);
cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
fmt, args);
va_end(args);
if(cur >= vt->tmpbuffer_len)
return;
vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
}
INTERNAL void vterm_push_output_sprintf_str(VTerm *vt, unsigned char ctrl, bool term, const char *fmt, ...)
{
size_t cur = 0;
if(ctrl) {
if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
ESC_S "%c", ctrl - 0x40);
else
cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len,
"%c", ctrl);
if(cur >= vt->tmpbuffer_len)
return;
}
va_list args;
va_start(args, fmt);
cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
fmt, args);
va_end(args);
if(cur >= vt->tmpbuffer_len)
return;
if(term) {
cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST
if(cur >= vt->tmpbuffer_len)
return;
}
vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
}
size_t vterm_output_get_buffer_size(const VTerm *vt)
{
return vt->outbuffer_len;
}
size_t vterm_output_get_buffer_current(const VTerm *vt)
{
return vt->outbuffer_cur;
}
size_t vterm_output_get_buffer_remaining(const VTerm *vt)
{
return vt->outbuffer_len - vt->outbuffer_cur;
}
size_t vterm_output_read(VTerm *vt, char *buffer, size_t len)
{
if(len > vt->outbuffer_cur)
len = vt->outbuffer_cur;
memcpy(buffer, vt->outbuffer, len);
if(len < vt->outbuffer_cur)
memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len);
vt->outbuffer_cur -= len;
return len;
}
VTermValueType vterm_get_attr_type(VTermAttr attr)
{
switch(attr) {
case VTERM_ATTR_BOLD: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_UNDERLINE: return VTERM_VALUETYPE_INT;
case VTERM_ATTR_ITALIC: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_BLINK: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_REVERSE: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_CONCEAL: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_STRIKE: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT;
case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR;
case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR;
case VTERM_ATTR_SMALL: return VTERM_VALUETYPE_BOOL;
case VTERM_ATTR_BASELINE: return VTERM_VALUETYPE_INT;
case VTERM_N_ATTRS: return 0;
}
return 0; /* UNREACHABLE */
}
VTermValueType vterm_get_prop_type(VTermProp prop)
{
switch(prop) {
case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL;
case VTERM_PROP_CURSORBLINK: return VTERM_VALUETYPE_BOOL;
case VTERM_PROP_ALTSCREEN: return VTERM_VALUETYPE_BOOL;
case VTERM_PROP_TITLE: return VTERM_VALUETYPE_STRING;
case VTERM_PROP_ICONNAME: return VTERM_VALUETYPE_STRING;
case VTERM_PROP_REVERSE: return VTERM_VALUETYPE_BOOL;
case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT;
case VTERM_PROP_MOUSE: return VTERM_VALUETYPE_INT;
case VTERM_N_PROPS: return 0;
}
return 0; /* UNREACHABLE */
}
void vterm_scroll_rect(VTermRect rect,
int downward,
int rightward,
int (*moverect)(VTermRect src, VTermRect dest, void *user),
int (*eraserect)(VTermRect rect, int selective, void *user),
void *user)
{
VTermRect src;
VTermRect dest;
if(abs(downward) >= rect.end_row - rect.start_row ||
abs(rightward) >= rect.end_col - rect.start_col) {
/* Scroll more than area; just erase the lot */
(*eraserect)(rect, 0, user);
return;
}
if(rightward >= 0) {
/* rect: [XXX................]
* src: [----------------]
* dest: [----------------]
*/
dest.start_col = rect.start_col;
dest.end_col = rect.end_col - rightward;
src.start_col = rect.start_col + rightward;
src.end_col = rect.end_col;
}
else {
/* rect: [................XXX]
* src: [----------------]
* dest: [----------------]
*/
int leftward = -rightward;
dest.start_col = rect.start_col + leftward;
dest.end_col = rect.end_col;
src.start_col = rect.start_col;
src.end_col = rect.end_col - leftward;
}
if(downward >= 0) {
dest.start_row = rect.start_row;
dest.end_row = rect.end_row - downward;
src.start_row = rect.start_row + downward;
src.end_row = rect.end_row;
}
else {
int upward = -downward;
dest.start_row = rect.start_row + upward;
dest.end_row = rect.end_row;
src.start_row = rect.start_row;
src.end_row = rect.end_row - upward;
}
if(moverect)
(*moverect)(dest, src, user);
if(downward > 0)
rect.start_row = rect.end_row - downward;
else if(downward < 0)
rect.end_row = rect.start_row - downward;
if(rightward > 0)
rect.start_col = rect.end_col - rightward;
else if(rightward < 0)
rect.end_col = rect.start_col - rightward;
(*eraserect)(rect, 0, user);
}
void vterm_copy_cells(VTermRect dest,
VTermRect src,
void (*copycell)(VTermPos dest, VTermPos src, void *user),
void *user)
{
int downward = src.start_row - dest.start_row;
int rightward = src.start_col - dest.start_col;
int init_row, test_row, init_col, test_col;
int inc_row, inc_col;
if(downward < 0) {
init_row = dest.end_row - 1;
test_row = dest.start_row - 1;
inc_row = -1;
}
else /* downward >= 0 */ {
init_row = dest.start_row;
test_row = dest.end_row;
inc_row = +1;
}
if(rightward < 0) {
init_col = dest.end_col - 1;
test_col = dest.start_col - 1;
inc_col = -1;
}
else /* rightward >= 0 */ {
init_col = dest.start_col;
test_col = dest.end_col;
inc_col = +1;
}
VTermPos pos;
for(pos.row = init_row; pos.row != test_row; pos.row += inc_row)
for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) {
VTermPos srcpos = { pos.row + downward, pos.col + rightward };
(*copycell)(pos, srcpos, user);
}
}
void vterm_check_version(int major, int minor)
{
if(major != VTERM_VERSION_MAJOR) {
fprintf(stderr, "libvterm major version mismatch; %d (wants) != %d (library)\n",
major, VTERM_VERSION_MAJOR);
exit(1);
}
if(minor > VTERM_VERSION_MINOR) {
fprintf(stderr, "libvterm minor version mismatch; %d (wants) > %d (library)\n",
minor, VTERM_VERSION_MINOR);
exit(1);
}
// Happy
}

View File

@@ -0,0 +1,296 @@
#ifndef __VTERM_INTERNAL_H__
#define __VTERM_INTERNAL_H__
#include "vterm.h"
#include <stdarg.h>
#if defined(__GNUC__)
# define INTERNAL __attribute__((visibility("internal")))
#else
# define INTERNAL
#endif
#ifdef DEBUG
# define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)
#else
# define DEBUG_LOG(...)
#endif
#define ESC_S "\x1b"
#define INTERMED_MAX 16
#define CSI_ARGS_MAX 16
#define CSI_LEADER_MAX 16
#define BUFIDX_PRIMARY 0
#define BUFIDX_ALTSCREEN 1
typedef struct VTermEncoding VTermEncoding;
typedef struct {
VTermEncoding *enc;
// This size should be increased if required by other stateful encodings
char data[4*sizeof(uint32_t)];
} VTermEncodingInstance;
struct VTermPen
{
VTermColor fg;
VTermColor bg;
unsigned int bold:1;
unsigned int underline:2;
unsigned int italic:1;
unsigned int blink:1;
unsigned int reverse:1;
unsigned int conceal:1;
unsigned int strike:1;
unsigned int font:4; /* To store 0-9 */
unsigned int small:1;
unsigned int baseline:2;
};
struct VTermState
{
VTerm *vt;
const VTermStateCallbacks *callbacks;
void *cbdata;
const VTermStateFallbacks *fallbacks;
void *fbdata;
int rows;
int cols;
/* Current cursor position */
VTermPos pos;
int at_phantom; /* True if we're on the "81st" phantom column to defer a wraparound */
int scrollregion_top;
int scrollregion_bottom; /* -1 means unbounded */
#define SCROLLREGION_BOTTOM(state) ((state)->scrollregion_bottom > -1 ? (state)->scrollregion_bottom : (state)->rows)
int scrollregion_left;
#define SCROLLREGION_LEFT(state) ((state)->mode.leftrightmargin ? (state)->scrollregion_left : 0)
int scrollregion_right; /* -1 means unbounded */
#define SCROLLREGION_RIGHT(state) ((state)->mode.leftrightmargin && (state)->scrollregion_right > -1 ? (state)->scrollregion_right : (state)->cols)
/* Bitvector of tab stops */
unsigned char *tabstops;
/* Primary and Altscreen; lineinfos[1] is lazily allocated as needed */
VTermLineInfo *lineinfos[2];
/* lineinfo will == lineinfos[0] or lineinfos[1], depending on altscreen */
VTermLineInfo *lineinfo;
#define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols)
#define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row)
/* Mouse state */
int mouse_col, mouse_row;
int mouse_buttons;
int mouse_flags;
#define MOUSE_WANT_CLICK 0x01
#define MOUSE_WANT_DRAG 0x02
#define MOUSE_WANT_MOVE 0x04
enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol;
/* Last glyph output, for Unicode recombining purposes */
uint32_t *combine_chars;
size_t combine_chars_size; // Number of ELEMENTS in the above
int combine_width; // The width of the glyph above
VTermPos combine_pos; // Position before movement
struct {
unsigned int keypad:1;
unsigned int cursor:1;
unsigned int autowrap:1;
unsigned int insert:1;
unsigned int newline:1;
unsigned int cursor_visible:1;
unsigned int cursor_blink:1;
unsigned int cursor_shape:2;
unsigned int alt_screen:1;
unsigned int origin:1;
unsigned int screen:1;
unsigned int leftrightmargin:1;
unsigned int bracketpaste:1;
unsigned int report_focus:1;
} mode;
VTermEncodingInstance encoding[4], encoding_utf8;
int gl_set, gr_set, gsingle_set;
struct VTermPen pen;
VTermColor default_fg;
VTermColor default_bg;
VTermColor colors[16]; // Store the 8 ANSI and the 8 ANSI high-brights only
int bold_is_highbright;
unsigned int protected_cell : 1;
/* Saved state under DEC mode 1048/1049 */
struct {
VTermPos pos;
struct VTermPen pen;
struct {
unsigned int cursor_visible:1;
unsigned int cursor_blink:1;
unsigned int cursor_shape:2;
} mode;
} saved;
/* Temporary state for DECRQSS parsing */
union {
char decrqss[4];
struct {
uint16_t mask;
enum {
SELECTION_INITIAL,
SELECTION_SELECTED,
SELECTION_QUERY,
SELECTION_SET_INITIAL,
SELECTION_SET,
} state : 8;
uint32_t recvpartial;
uint32_t sendpartial;
} selection;
} tmp;
struct {
const VTermSelectionCallbacks *callbacks;
void *user;
char *buffer;
size_t buflen;
} selection;
};
struct VTerm
{
const VTermAllocatorFunctions *allocator;
void *allocdata;
int rows;
int cols;
struct {
unsigned int utf8:1;
unsigned int ctrl8bit:1;
} mode;
struct {
enum VTermParserState {
NORMAL,
CSI_LEADER,
CSI_ARGS,
CSI_INTERMED,
DCS_COMMAND,
/* below here are the "string states" */
OSC_COMMAND,
OSC,
DCS,
APC,
PM,
SOS,
} state;
bool in_esc : 1;
int intermedlen;
char intermed[INTERMED_MAX];
union {
struct {
int leaderlen;
char leader[CSI_LEADER_MAX];
int argi;
long args[CSI_ARGS_MAX];
} csi;
struct {
int command;
} osc;
struct {
int commandlen;
char command[CSI_LEADER_MAX];
} dcs;
} v;
const VTermParserCallbacks *callbacks;
void *cbdata;
bool string_initial;
bool emit_nul;
} parser;
/* len == malloc()ed size; cur == number of valid bytes */
VTermOutputCallback *outfunc;
void *outdata;
char *outbuffer;
size_t outbuffer_len;
size_t outbuffer_cur;
char *tmpbuffer;
size_t tmpbuffer_len;
VTermState *state;
VTermScreen *screen;
};
struct VTermEncoding {
void (*init) (VTermEncoding *enc, void *data);
void (*decode)(VTermEncoding *enc, void *data,
uint32_t cp[], int *cpi, int cplen,
const char bytes[], size_t *pos, size_t len);
};
typedef enum {
ENC_UTF8,
ENC_SINGLE_94
} VTermEncodingType;
void *vterm_allocator_malloc(VTerm *vt, size_t size);
void vterm_allocator_free(VTerm *vt, void *ptr);
void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len);
void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args);
void vterm_push_output_sprintf(VTerm *vt, const char *format, ...);
void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...);
void vterm_push_output_sprintf_str(VTerm *vt, unsigned char ctrl, bool term, const char *fmt, ...);
void vterm_state_free(VTermState *state);
void vterm_state_newpen(VTermState *state);
void vterm_state_resetpen(VTermState *state);
void vterm_state_setpen(VTermState *state, const long args[], int argcount);
int vterm_state_getpen(VTermState *state, long args[], int argcount);
void vterm_state_savepen(VTermState *state, int save);
enum {
C1_SS3 = 0x8f,
C1_DCS = 0x90,
C1_CSI = 0x9b,
C1_ST = 0x9c,
C1_OSC = 0x9d,
};
void vterm_state_push_output_sprintf_CSI(VTermState *vts, const char *format, ...);
void vterm_screen_free(VTermScreen *screen);
VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation);
int vterm_unicode_width(uint32_t codepoint);
int vterm_unicode_is_combining(uint32_t codepoint);
#endif

View File

@@ -0,0 +1,8 @@
libdir=@LIBDIR@
includedir=@INCDIR@
Name: vterm
Description: Abstract VT220/Xterm/ECMA-48 emulation library
Version: 0.3.1
Libs: -L${libdir} -lvterm
Cflags: -I${includedir}

33
src/libs/3rdparty/libvterm/vterm.qbs vendored Normal file
View File

@@ -0,0 +1,33 @@
Project {
QtcLibrary {
name: "vterm"
type: "staticlibrary"
Depends { name: "cpp" }
cpp.includePaths: base.concat("include")
Group {
prefix: "src/"
files: [
"encoding.c",
"fullwidth.inc",
"keyboard.c",
"mouse.c",
"parser.c",
"pen.c",
"rect.h",
"screen.c",
"state.c",
"unicode.c",
"utf8.h",
"vterm.c",
"vterm_internal.h",
]
}
Export {
Depends { name: "cpp" }
cpp.includePaths: base.concat("include")
}
}
}

19
src/libs/3rdparty/winpty/.gitattributes vendored Normal file
View File

@@ -0,0 +1,19 @@
* text=auto
*.bat text eol=crlf
*.c text
*.cc text
*.gyp text
*.gypi text
*.h text
*.ps1 text eol=crlf
*.rst text
*.sh text
*.txt text
.gitignore text
.gitattributes text
Makefile text
configure text
*.sh eol=lf
configure eol=lf
VERSION.txt eol=lf

16
src/libs/3rdparty/winpty/.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
*.sln
*.suo
*.vcxproj
*.vcxproj.filters
*.pyc
winpty.sdf
winpty.opensdf
/config.mk
/build
/build-gyp
/build-libpty
/ship/packages
/ship/tmp
/src/Default
/src/Release
/src/gen

View File

@@ -0,0 +1 @@
add_subdirectory(src)

21
src/libs/3rdparty/winpty/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2011-2016 Ryan Prichard
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

151
src/libs/3rdparty/winpty/README.md vendored Normal file
View File

@@ -0,0 +1,151 @@
# winpty
[![Build Status](https://ci.appveyor.com/api/projects/status/69tb9gylsph1ee1x/branch/master?svg=true)](https://ci.appveyor.com/project/rprichard/winpty/branch/master)
winpty is a Windows software package providing an interface similar to a Unix
pty-master for communicating with Windows console programs. The package
consists of a library (libwinpty) and a tool for Cygwin and MSYS for running
Windows console programs in a Cygwin/MSYS pty.
The software works by starting the `winpty-agent.exe` process with a new,
hidden console window, which bridges between the console API and terminal
input/output escape codes. It polls the hidden console's screen buffer for
changes and generates a corresponding stream of output.
The Unix adapter allows running Windows console programs (e.g. CMD, PowerShell,
IronPython, etc.) under `mintty` or Cygwin's `sshd` with
properly-functioning input (e.g. arrow and function keys) and output (e.g. line
buffering). The library could be also useful for writing a non-Cygwin SSH
server.
## Supported Windows versions
winpty runs on Windows XP through Windows 10, including server versions. It
can be compiled into either 32-bit or 64-bit binaries.
## Cygwin/MSYS adapter (`winpty.exe`)
### Prerequisites
You need the following to build winpty:
* A Cygwin or MSYS installation
* GNU make
* A MinGW g++ toolchain capable of compiling C++11 code to build `winpty.dll`
and `winpty-agent.exe`
* A g++ toolchain targeting Cygwin or MSYS to build `winpty.exe`
Winpty requires two g++ toolchains as it is split into two parts. The
`winpty.dll` and `winpty-agent.exe` binaries interface with the native
Windows command prompt window so they are compiled with the native MinGW
toolchain. The `winpty.exe` binary interfaces with the MSYS/Cygwin terminal so
it is compiled with the MSYS/Cygwin toolchain.
MinGW appears to be split into two distributions -- MinGW (creates 32-bit
binaries) and MinGW-w64 (creates both 32-bit and 64-bit binaries). Either
one is generally acceptable.
#### Cygwin packages
The default g++ compiler for Cygwin targets Cygwin itself, but Cygwin also
packages MinGW-w64 compilers. As of this writing, the necessary packages are:
* Either `mingw64-i686-gcc-g++` or `mingw64-x86_64-gcc-g++`. Select the
appropriate compiler for your CPU architecture.
* `gcc-g++`
* `make`
As of this writing (2016-01-23), only the MinGW-w64 compiler is acceptable.
The MinGW compiler (e.g. from the `mingw-gcc-g++` package) is no longer
maintained and is too buggy.
#### MSYS packages
For the original MSYS, use the `mingw-get` tool (MinGW Installation Manager),
and select at least these components:
* `mingw-developer-toolkit`
* `mingw32-base`
* `mingw32-gcc-g++`
* `msys-base`
* `msys-system-builder`
When running `./configure`, make sure that `mingw32-g++` is in your
`PATH`. It will be in the `C:\MinGW\bin` directory.
#### MSYS2 packages
For MSYS2, use `pacman` and install at least these packages:
* `msys/gcc`
* `mingw32/mingw-w64-i686-gcc` or `mingw64/mingw-w64-x86_64-gcc`. Select
the appropriate compiler for your CPU architecture.
* `make`
MSYS2 provides three start menu shortcuts for starting MSYS2:
* MinGW-w64 Win32 Shell
* MinGW-w64 Win64 Shell
* MSYS2 Shell
To build winpty, use the MinGW-w64 {Win32,Win64} shortcut of the architecture
matching MSYS2. These shortcuts will put the g++ compiler from the
`{mingw32,mingw64}/mingw-w64-{i686,x86_64}-gcc` packages into the `PATH`.
Alternatively, instead of installing `mingw32/mingw-w64-i686-gcc` or
`mingw64/mingw-w64-x86_64-gcc`, install the `mingw-w64-cross-gcc` and
`mingw-w64-cross-crt-git` packages. These packages install cross-compilers
into `/opt/bin`, and then any of the three shortcuts will work.
### Building the Unix adapter
In the project directory, run `./configure`, then `make`, then `make install`.
By default, winpty is installed into `/usr/local`. Pass `PREFIX=<path>` to
`make install` to override this default.
### Using the Unix adapter
To run a Windows console program in `mintty` or Cygwin `sshd`, prepend
`winpty` to the command-line:
$ winpty powershell
Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.
PS C:\rprichard\proj\winpty> 10 + 20
30
PS C:\rprichard\proj\winpty> exit
## Embedding winpty / MSVC compilation
See `src/include/winpty.h` for the prototypes of functions exported by
`winpty.dll`.
Only the `winpty.exe` binary uses Cygwin; all the other binaries work without
it and can be compiled with either MinGW or MSVC. To compile using MSVC,
download gyp and run `gyp -I configurations.gypi` in the `src` subdirectory.
This will generate a `winpty.sln` and associated project files. See the
`src/winpty.gyp` and `src/configurations.gypi` files for notes on dealing with
MSVC versions and different architectures.
Compiling winpty with MSVC currently requires MSVC 2013 or newer.
## Debugging winpty
winpty comes with a tool for collecting timestamped debugging output. To use
it:
1. Run `winpty-debugserver.exe` on the same computer as winpty.
2. Set the `WINPTY_DEBUG` environment variable to `trace` for the
`winpty.exe` process and/or the process using `libwinpty.dll`.
winpty also recognizes a `WINPTY_SHOW_CONSOLE` environment variable. Set it
to 1 to prevent winpty from hiding the console window.
## Copyright
This project is distributed under the MIT license (see the `LICENSE` file in
the project root).
By submitting a pull request for this project, you agree to license your
contribution under the MIT license to this project.

280
src/libs/3rdparty/winpty/RELEASES.md vendored Normal file
View File

@@ -0,0 +1,280 @@
# Next Version
Input handling changes:
* Improve Ctrl-C handling with programs that use unprocessed input. (e.g.
Ctrl-C now cancels input with PowerShell on Windows 10.)
[#116](https://github.com/rprichard/winpty/issues/116)
* Fix a theoretical issue with input event ordering.
[#117](https://github.com/rprichard/winpty/issues/117)
* Ctrl/Shift+{Arrow,Home,End} keys now work with IntelliJ.
[#118](https://github.com/rprichard/winpty/issues/118)
# Version 0.4.3 (2017-05-17)
Input handling changes:
* winpty sets `ENHANCED_KEY` for arrow and navigation keys. This fixes an
issue with the Ruby REPL.
[#99](https://github.com/rprichard/winpty/issues/99)
* AltGr keys are handled better now.
[#109](https://github.com/rprichard/winpty/issues/109)
* In `ENABLE_VIRTUAL_TERMINAL_INPUT` mode, when typing Home/End with a
modifier (e.g. Ctrl), winpty now generates an H/F escape sequence like
`^[[1;5F` rather than a 1/4 escape like `^[[4;5~`.
[#114](https://github.com/rprichard/winpty/issues/114)
Resizing and scraping fixes:
* winpty now synthesizes a `WINDOW_BUFFER_SIZE_EVENT` event after resizing
the console to better propagate window size changes to console programs.
In particular, this affects WSL and Cygwin.
[#110](https://github.com/rprichard/winpty/issues/110)
* Better handling of resizing for certain full-screen programs, like
WSL less.
[#112](https://github.com/rprichard/winpty/issues/112)
* Hide the cursor if it's currently outside the console window. This change
fixes an issue with Far Manager.
[#113](https://github.com/rprichard/winpty/issues/113)
* winpty now avoids using console fonts smaller than 5px high to improve
half-vs-full-width character handling. See
https://github.com/Microsoft/vscode/issues/19665.
[b4db322010](https://github.com/rprichard/winpty/commit/b4db322010d2d897e6c496fefc4f0ecc9b84c2f3)
Cygwin/MSYS adapter fix:
* The way the `winpty` Cygwin/MSYS2 adapter searches for the program to
launch changed. It now resolves symlinks and searches the PATH explicitly.
[#81](https://github.com/rprichard/winpty/issues/81)
[#98](https://github.com/rprichard/winpty/issues/98)
This release does not include binaries for the old MSYS1 project anymore.
MSYS2 will continue to be supported. See
https://github.com/rprichard/winpty/issues/97.
# Version 0.4.2 (2017-01-18)
This release improves WSL support (i.e. Bash-on-Windows):
* winpty generates more correct input escape sequences for WSL programs that
enable an alternate input mode using DECCKM. This bug affected arrow keys
and Home/End in WSL programs such as `vim`, `mc`, and `less`.
[#90](https://github.com/rprichard/winpty/issues/90)
* winpty now recognizes the `COMMON_LVB_REVERSE_VIDEO` and
`COMMON_LVB_UNDERSCORE` text attributes. The Windows console uses these
attributes to implement the SGR.4(Underline) and SGR.7(Negative) modes in
its VT handling. This change affects WSL pager status bars, man pages, etc.
The build system no longer has a "version suffix" mechanism, so passing
`VERSION_SUFFIX=<suffix>` to make or `-D VERSION_SUFFIX=<suffix>` to gyp now
has no effect. AFAIK, the mechanism was never used publicly.
[67a34b6c03](https://github.com/rprichard/winpty/commit/67a34b6c03557a5c2e0a2bdd502c2210921d8f3e)
# Version 0.4.1 (2017-01-03)
Bug fixes:
* This version fixes a bug where the `winpty-agent.exe` process could read
past the end of a buffer.
[#94](https://github.com/rprichard/winpty/issues/94)
# Version 0.4.0 (2016-06-28)
The winpty library has a new API that should be easier for embedding.
[880c00c69e](https://github.com/rprichard/winpty/commit/880c00c69eeca73643ddb576f02c5badbec81f56)
User-visible changes:
* winpty now automatically puts the terminal into mouse mode when it detects
that the console has left QuickEdit mode. The `--mouse` option still forces
the terminal into mouse mode. In principle, an option could be added to
suppress terminal mode, but hopefully it won't be necessary. There is a
script in the `misc` subdirectory, `misc/ConinMode.ps1`, that can change
the QuickEdit mode from the command-line.
* winpty now passes keyboard escapes to `bash.exe` in the Windows Subsystem
for Linux.
[#82](https://github.com/rprichard/winpty/issues/82)
Bug fixes:
* By default, `winpty.dll` avoids calling `SetProcessWindowStation` within
the calling process.
[#58](https://github.com/rprichard/winpty/issues/58)
* Fixed an uninitialized memory bug that could have crashed winpty.
[#80](https://github.com/rprichard/winpty/issues/80)
* winpty now works better with very large and very small terminal windows.
It resizes the console font according to the number of columns.
[#61](https://github.com/rprichard/winpty/issues/61)
* winpty no longer uses Mark to freeze the console on Windows 10. The Mark
command could interfere with the cursor position, corrupting the data in
the screen buffer.
[#79](https://github.com/rprichard/winpty/issues/79)
# Version 0.3.0 (2016-05-20)
User-visible changes:
* The UNIX adapter is renamed from `console.exe` to `winpty.exe` to be
consistent with MSYS2. The name `winpty.exe` is less likely to conflict
with another program and is easier to search for online (e.g. for someone
unfamiliar with winpty).
* The UNIX adapter now clears the `TERM` variable.
[#43](https://github.com/rprichard/winpty/issues/43)
* An escape character appearing in a console screen buffer cell is converted
to a '?'.
[#47](https://github.com/rprichard/winpty/issues/47)
Bug fixes:
* A major bug affecting XP users was fixed.
[#67](https://github.com/rprichard/winpty/issues/67)
* Fixed an incompatibility with ConEmu where winpty hung if ConEmu's
"Process 'start'" feature was enabled.
[#70](https://github.com/rprichard/winpty/issues/70)
* Fixed a bug where `cmd.exe` sometimes printed the message,
`Not enough storage is available to process this command.`.
[#74](https://github.com/rprichard/winpty/issues/74)
Many changes internally:
* The codebase is switched from C++03 to C++11 and uses exceptions internally.
No exceptions are thrown across the C APIs defined in `winpty.h`.
* This version drops support for the original MinGW compiler packaged with
Cygwin (`i686-pc-mingw32-g++`). The MinGW-w64 compiler is still supported,
as is the MinGW distributed at mingw.org. Compiling with MSVC now requires
MSVC 2013 or newer. Windows XP is still supported.
[ec3eae8df5](https://github.com/rprichard/winpty/commit/ec3eae8df5bbbb36d7628d168b0815638d122f37)
* Pipe security is improved. winpty works harder to produce unique pipe names
and includes a random component in the name. winpty secures pipes with a
DACL that prevents arbitrary users from connecting to its pipes. winpty now
passes `PIPE_REJECT_REMOTE_CLIENTS` on Vista and up, and it verifies that
the pipe client PID is correct, again on Vista and up. When connecting to a
named pipe, winpty uses the `SECURITY_IDENTIFICATION` flag to restrict
impersonation. Previous versions *should* still be secure.
* `winpty-debugserver.exe` now has an `--everyone` flag that allows capturing
debug output from other users.
* The code now compiles cleanly with MSVC's "Security Development Lifecycle"
(`/SDL`) checks enabled.
# Version 0.2.2 (2016-02-25)
Minor bug fixes and enhancements:
* Fix a bug that generated spurious mouse input records when an incomplete
mouse escape sequence was seen.
* Fix a buffer overflow bug in `winpty-debugserver.exe` affecting messages of
exactly 4096 bytes.
* For MSVC builds, add a `src/configurations.gypi` file that can be included
on the gyp command-line to enable 32-bit and 64-bit builds.
* `winpty-agent --show-input` mode: Flush stdout after each line.
* Makefile builds: generate a `build/winpty.lib` import library to accompany
`build/winpty.dll`.
# Version 0.2.1 (2015-12-19)
* The main project source was moved into a `src` directory for better code
organization and to fix
[#51](https://github.com/rprichard/winpty/issues/51).
* winpty recognizes many more escape sequences, including:
* putty/rxvt's F1-F4 keys
[#40](https://github.com/rprichard/winpty/issues/40)
* the Linux virtual console's F1-F5 keys
* the "application numpad" keys (e.g. enabled with DECPAM)
* Fixed handling of Shift-Alt-O and Alt-[.
* Added support for mouse input. The UNIX adapter has a `--mouse` argument
that puts the terminal into mouse mode, but the agent recognizes mouse
input even without the argument. The agent recognizes double-clicks using
Windows' double-click interval setting (i.e. GetDoubleClickTime).
[#57](https://github.com/rprichard/winpty/issues/57)
Changes to debugging interfaces:
* The `WINPTY_DEBUG` variable is now a comma-separated list. The old
behavior (i.e. tracing) is enabled with `WINPTY_DEBUG=trace`.
* The UNIX adapter program now has a `--showkey` argument that dumps input
bytes.
* The `winpty-agent.exe` program has a `--show-input` argument that dumps
`INPUT_RECORD` records. (It omits mouse events unless `--with-mouse` is
also specified.) The agent also responds to `WINPTY_DEBUG=trace,input`,
which logs input bytes and synthesized console events, and it responds to
`WINPTY_DEBUG=trace,dump_input_map`, which dumps the internal table of
escape sequences.
# Version 0.2.0 (2015-11-13)
No changes to the API, but many small changes to the implementation. The big
changes include:
* Support for 64-bit Cygwin and MSYS2
* Support for Windows 10
* Better Unicode support (especially East Asian languages)
Details:
* The `configure` script recognizes 64-bit Cygwin and MSYS2 environments and
selects the appropriate compiler.
* winpty works much better with the upgraded console in Windows 10. The
`conhost.exe` hang can still occur, but only with certain programs, and
is much less likely to occur. With the new console, use Mark instead of
SelectAll, for better performance.
[#31](https://github.com/rprichard/winpty/issues/31)
[#30](https://github.com/rprichard/winpty/issues/30)
[#53](https://github.com/rprichard/winpty/issues/53)
* The UNIX adapter now calls `setlocale(LC_ALL, "")` to set the locale.
* Improved Unicode support. When a console is started with an East Asian code
page, winpty now chooses an East Asian font rather than Consolas / Lucida
Console. Selecting the right font helps synchronize character widths
between the console and terminal. (It's not perfect, though.)
[#41](https://github.com/rprichard/winpty/issues/41)
* winpty now more-or-less works with programs that change the screen buffer
or resize the original screen buffer. If the screen buffer height changes,
winpty switches to a "direct mode", where it makes no effort to track
scrolling. In direct mode, it merely syncs snapshots of the console to the
terminal. Caveats:
* Changing the screen buffer (i.e. `SetConsoleActiveScreenBuffer`)
breaks winpty on Windows 7. This problem can eventually be mitigated,
but never completely fixed, due to Windows 7 bugginess.
* Resizing the original screen buffer can hang `conhost.exe` on Windows 10.
Enabling the legacy console is a workaround.
* If a program changes the screen buffer and then exits, relying on the OS
to restore the original screen buffer, that restoration probably will not
happen with winpty. winpty's behavior can probably be improved here.
* Improved color handling:
* DkGray-on-Black text was previously hiddenly completely. Now it is
output as DkGray, with a fallback to LtGray on terminals that don't
recognize the intense colors.
[#39](https://github.com/rprichard/winpty/issues/39).
* The console is always initialized to LtGray-on-Black, regardless of the
user setting, which matches the console color heuristic, which translates
LtGray-on-Black to "reset SGR parameters."
* Shift-Tab is recognized correctly now.
[#19](https://github.com/rprichard/winpty/issues/19)
* Add a `--version` argument to `winpty-agent.exe` and the UNIX adapter. The
argument reports the nominal version (i.e. the `VERSION.txt`) file, with a
"VERSION_SUFFIX" appended (defaulted to `-dev`), and a git commit hash, if
the `git` command successfully reports a hash during the build. The `git`
command is invoked by either `make` or `gyp`.
* The agent now combines `ReadConsoleOutputW` calls when it polls the console
buffer for changes, which may slightly reduce its CPU overhead.
[#44](https://github.com/rprichard/winpty/issues/44).
* A `gyp` file is added to help compile with MSVC.
* The code can now be compiled as C++11 code, though it isn't by default.
[bde8922e08](https://github.com/rprichard/winpty/commit/bde8922e08c3638e01ecc7b581b676c314163e3c)
* If winpty can't create a new window station, it charges ahead rather than
aborting. This situation might happen if winpty were started from an SSH
session.
* Debugging improvements:
* `WINPTYDBG` is renamed to `WINPTY_DEBUG`, and a new `WINPTY_SHOW_CONSOLE`
variable keeps the underlying console visible.
* A `winpty-debugserver.exe` program is built and shipped by default. It
collects the trace output enabled with `WINPTY_DEBUG`.
* The `Makefile` build of winpty now compiles `winpty-agent.exe` and
`winpty.dll` with -O2.
# Version 0.1.1 (2012-07-28)
Minor bugfix release.
# Version 0.1 (2012-04-17)
Initial release.

1
src/libs/3rdparty/winpty/VERSION.txt vendored Normal file
View File

@@ -0,0 +1 @@
0.4.4-dev

16
src/libs/3rdparty/winpty/appveyor.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
image: Visual Studio 2015
init:
- C:\msys64\usr\bin\bash --login -c "pacman -S --needed --noconfirm --noprogressbar msys/make msys/tar msys/gcc mingw-w64-cross-toolchain"
- C:\cygwin\setup-x86 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make
- C:\cygwin64\setup-x86_64 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make
build_script:
- C:\Python27-x64\python.exe ship\ship.py --kind msys2 --arch x64 --syspath C:\msys64
- C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch ia32 --syspath C:\cygwin
- C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch x64 --syspath C:\cygwin64
- C:\Python27-x64\python.exe ship\make_msvc_package.py
artifacts:
- path: ship\packages\*.tar.gz
- path: ship\packages\*.zip

167
src/libs/3rdparty/winpty/configure vendored Normal file
View File

@@ -0,0 +1,167 @@
#!/bin/bash
#
# Copyright (c) 2011-2015 Ryan Prichard
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# findTool(desc, commandList)
#
# Searches commandLine for the first command in the PATH and returns it.
# Prints an error and aborts the script if no match is found.
#
FINDTOOL_OUT=""
function findTool {
DESC=$1
OPTIONS=$2
for CMD in ${OPTIONS}; do
if (which $CMD &>/dev/null) then
echo "Found $DESC: $CMD"
FINDTOOL_OUT="$CMD"
return
fi
done
echo "Error: could not find $DESC. One of these should be in your PATH:"
for CMD in ${OPTIONS}; do
echo " * $CMD"
done
exit 1
}
IS_CYGWIN=0
IS_MSYS1=0
IS_MSYS2=0
# Link parts of the Cygwin binary statically to aid in redistribution? The
# binary still links dynamically against the main DLL. The MinGW binaries are
# also statically linked and therefore depend only on Windows DLLs. I started
# linking the Cygwin/MSYS binary statically, because G++ 4.7 changed the
# Windows C++ ABI.
UNIX_LDFLAGS_STATIC='-static -static-libgcc -static-libstdc++'
# Detect the environment -- Cygwin or MSYS.
case $(uname -s) in
CYGWIN*)
echo 'uname -s identifies a Cygwin environment.'
IS_CYGWIN=1
case $(uname -m) in
i686)
echo 'uname -m identifies an i686 environment.'
UNIX_CXX=i686-pc-cygwin-g++
MINGW_CXX=i686-w64-mingw32-g++
;;
x86_64)
echo 'uname -m identifies an x86_64 environment.'
UNIX_CXX=x86_64-pc-cygwin-g++
MINGW_CXX=x86_64-w64-mingw32-g++
;;
*)
echo 'Error: uname -m did not match either i686 or x86_64.'
exit 1
;;
esac
;;
MSYS*|MINGW*)
# MSYS2 notes:
# - MSYS2 offers two shortcuts to open an environment:
# - MinGW-w64 Win32 Shell. This env reports a `uname -s` of
# MINGW32_NT-6.1 on 32-bit Win7. The MinGW-w64 compiler
# (i686-w64-mingw32-g++.exe) is in the PATH.
# - MSYS2 Shell. `uname -s` instead reports MSYS_NT-6.1.
# The i686-w64-mingw32-g++ compiler is not in the PATH.
# - MSYS2 appears to use MinGW-w64, not the older mingw.org.
# MSYS notes:
# - `uname -s` is always MINGW32_NT-6.1 on Win7.
echo 'uname -s identifies an MSYS/MSYS2 environment.'
case $(uname -m) in
i686)
echo 'uname -m identifies an i686 environment.'
UNIX_CXX=i686-pc-msys-g++
if echo "$(uname -r)" | grep '^1[.]' > /dev/null; then
# The MSYS-targeting compiler for the original 32-bit-only
# MSYS does not recognize the -static-libstdc++ flag, and
# it does not work with -static, because it tries to link
# statically with the core MSYS library and fails.
#
# Distinguish between the two using the major version
# number of `uname -r`:
#
# MSYS uname -r: 1.0.18(0.48/3/2)
# MSYS2 uname -r: 2.0.0(0.284/5/3)
#
# This is suboptimal because MSYS2 is not actually the
# second version of MSYS--it's a brand-new fork of Cygwin.
#
IS_MSYS1=1
UNIX_LDFLAGS_STATIC=
MINGW_CXX=mingw32-g++
else
IS_MSYS2=1
MINGW_CXX=i686-w64-mingw32-g++.exe
fi
;;
x86_64)
echo 'uname -m identifies an x86_64 environment.'
IS_MSYS2=1
UNIX_CXX=x86_64-pc-msys-g++
MINGW_CXX=x86_64-w64-mingw32-g++
;;
*)
echo 'Error: uname -m did not match either i686 or x86_64.'
exit 1
;;
esac
;;
*)
echo 'Error: uname -s did not match either CYGWIN* or MINGW*.'
exit 1
;;
esac
# Search the PATH and pick the first match.
findTool "Cygwin/MSYS G++ compiler" "$UNIX_CXX"
UNIX_CXX=$FINDTOOL_OUT
findTool "MinGW G++ compiler" "$MINGW_CXX"
MINGW_CXX=$FINDTOOL_OUT
# Write config files.
echo Writing config.mk
echo UNIX_CXX=$UNIX_CXX > config.mk
echo UNIX_LDFLAGS_STATIC=$UNIX_LDFLAGS_STATIC >> config.mk
echo MINGW_CXX=$MINGW_CXX >> config.mk
if test $IS_MSYS1 = 1; then
echo UNIX_CXXFLAGS += -DWINPTY_TARGET_MSYS1 >> config.mk
# The MSYS1 MinGW compiler has a bug that prevents inclusion of algorithm
# and math.h in normal C++11 mode. The workaround is to enable the gnu++11
# mode instead. The bug was fixed on 2015-07-31, but as of 2016-02-26, the
# fix apparently hasn't been released. See
# http://ehc.ac/p/mingw/bugs/2250/.
echo MINGW_ENABLE_CXX11_FLAG := -std=gnu++11 >> config.mk
fi
if test -d .git -a -f .git/HEAD -a -f .git/index && git rev-parse HEAD >&/dev/null; then
echo "Commit info: git"
echo 'COMMIT_HASH = $(shell git rev-parse HEAD)' >> config.mk
echo 'COMMIT_HASH_DEP := config.mk .git/HEAD .git/index' >> config.mk
else
echo "Commit info: none"
echo 'COMMIT_HASH := none' >> config.mk
echo 'COMMIT_HASH_DEP := config.mk' >> config.mk
fi

View File

@@ -0,0 +1,2 @@
*.exe
UnixEcho

View File

@@ -0,0 +1,90 @@
#include <windows.h>
#include <cassert>
#include "TestUtil.cc"
void dumpInfoToTrace() {
CONSOLE_SCREEN_BUFFER_INFO info;
assert(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info));
trace("win=(%d,%d,%d,%d)",
(int)info.srWindow.Left,
(int)info.srWindow.Top,
(int)info.srWindow.Right,
(int)info.srWindow.Bottom);
trace("buf=(%d,%d)",
(int)info.dwSize.X,
(int)info.dwSize.Y);
trace("cur=(%d,%d)",
(int)info.dwCursorPosition.X,
(int)info.dwCursorPosition.Y);
}
int main(int argc, char *argv[]) {
if (argc == 1) {
startChildProcess(L"CHILD");
return 0;
}
setWindowPos(0, 0, 1, 1);
if (false) {
// Reducing the buffer height can move the window up.
setBufferSize(80, 25);
setWindowPos(0, 20, 80, 5);
Sleep(2000);
setBufferSize(80, 10);
}
if (false) {
// Reducing the buffer height moves the window up and the buffer
// contents up too.
setBufferSize(80, 25);
setWindowPos(0, 20, 80, 5);
setCursorPos(0, 20);
printf("TEST1\nTEST2\nTEST3\nTEST4\n");
fflush(stdout);
Sleep(2000);
setBufferSize(80, 10);
}
if (false) {
// Reducing the buffer width can move the window left.
setBufferSize(80, 25);
setWindowPos(40, 0, 40, 25);
Sleep(2000);
setBufferSize(60, 25);
}
if (false) {
// Sometimes the buffer contents are shifted up; sometimes they're
// shifted down. It seems to depend on the cursor position?
// setBufferSize(80, 25);
// setWindowPos(0, 20, 80, 5);
// setCursorPos(0, 20);
// printf("TESTa\nTESTb\nTESTc\nTESTd\nTESTe");
// fflush(stdout);
// setCursorPos(0, 0);
// printf("TEST1\nTEST2\nTEST3\nTEST4\nTEST5");
// fflush(stdout);
// setCursorPos(0, 24);
// Sleep(5000);
// setBufferSize(80, 24);
setBufferSize(80, 20);
setWindowPos(0, 10, 80, 10);
setCursorPos(0, 18);
printf("TEST1\nTEST2");
fflush(stdout);
setCursorPos(0, 18);
Sleep(2000);
setBufferSize(80, 18);
}
dumpInfoToTrace();
Sleep(30000);
return 0;
}

View File

@@ -0,0 +1,53 @@
// A test program for CreateConsoleScreenBuffer / SetConsoleActiveScreenBuffer
//
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <io.h>
#include <cassert>
#include "TestUtil.cc"
int main()
{
HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE childBuffer = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
SetConsoleActiveScreenBuffer(childBuffer);
while (true) {
char buf[1024];
CONSOLE_SCREEN_BUFFER_INFO info;
assert(GetConsoleScreenBufferInfo(origBuffer, &info));
trace("child.size=(%d,%d)", (int)info.dwSize.X, (int)info.dwSize.Y);
trace("child.cursor=(%d,%d)", (int)info.dwCursorPosition.X, (int)info.dwCursorPosition.Y);
trace("child.window=(%d,%d,%d,%d)",
(int)info.srWindow.Left, (int)info.srWindow.Top,
(int)info.srWindow.Right, (int)info.srWindow.Bottom);
trace("child.maxSize=(%d,%d)", (int)info.dwMaximumWindowSize.X, (int)info.dwMaximumWindowSize.Y);
int ch = getch();
sprintf(buf, "%02x\n", ch);
DWORD actual = 0;
WriteFile(childBuffer, buf, strlen(buf), &actual, NULL);
if (ch == 0x1b/*ESC*/ || ch == 0x03/*CTRL-C*/)
break;
if (ch == 'b') {
setBufferSize(origBuffer, 40, 25);
} else if (ch == 'w') {
setWindowPos(origBuffer, 1, 1, 38, 23);
} else if (ch == 'c') {
setCursorPos(origBuffer, 10, 10);
}
}
SetConsoleActiveScreenBuffer(origBuffer);
return 0;
}

View File

@@ -0,0 +1,72 @@
/*
* Demonstrates that console clearing sets each cell's character to SP, not
* NUL, and it sets the attribute of each cell to the current text attribute.
*
* This confirms the MSDN instruction in the "Clearing the Screen" article.
* https://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx
* It advises using GetConsoleScreenBufferInfo to get the current text
* attribute, then FillConsoleOutputCharacter and FillConsoleOutputAttribute to
* write to the console buffer.
*/
#include <windows.h>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include "TestUtil.cc"
int main(int argc, char *argv[]) {
if (argc == 1) {
startChildProcess(L"CHILD");
return 0;
}
const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(conout, 0x24);
system("cls");
setWindowPos(0, 0, 1, 1);
setBufferSize(80, 25);
setWindowPos(0, 0, 80, 25);
CHAR_INFO buf;
COORD bufSize = { 1, 1 };
COORD bufCoord = { 0, 0 };
SMALL_RECT rect = { 5, 5, 5, 5 };
BOOL ret;
DWORD actual;
COORD writeCoord = { 5, 5 };
// After cls, each cell's character is a space, and its attributes are the
// default text attributes.
ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect);
assert(ret && buf.Char.UnicodeChar == L' ' && buf.Attributes == 0x24);
// Nevertheless, it is possible to change a cell to NUL.
ret = FillConsoleOutputCharacterW(conout, L'\0', 1, writeCoord, &actual);
assert(ret && actual == 1);
ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect);
assert(ret && buf.Char.UnicodeChar == L'\0' && buf.Attributes == 0x24);
// As well as a 0 attribute. (As one would expect, the cell is
// black-on-black.)
ret = FillConsoleOutputAttribute(conout, 0, 1, writeCoord, &actual);
assert(ret && actual == 1);
ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect);
assert(ret && buf.Char.UnicodeChar == L'\0' && buf.Attributes == 0);
ret = FillConsoleOutputCharacterW(conout, L'X', 1, writeCoord, &actual);
assert(ret && actual == 1);
ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect);
assert(ret && buf.Char.UnicodeChar == L'X' && buf.Attributes == 0);
// The 'X' is invisible.
countDown(3);
ret = FillConsoleOutputAttribute(conout, 0x42, 1, writeCoord, &actual);
assert(ret && actual == 1);
countDown(5);
}

View File

@@ -0,0 +1,117 @@
#include <windows.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
static HANDLE getConin() {
HANDLE conin = GetStdHandle(STD_INPUT_HANDLE);
if (conin == INVALID_HANDLE_VALUE) {
fprintf(stderr, "error: cannot get stdin\n");
exit(1);
}
return conin;
}
static DWORD getConsoleMode() {
DWORD mode = 0;
if (!GetConsoleMode(getConin(), &mode)) {
fprintf(stderr, "error: GetConsoleMode failed (is stdin a console?)\n");
exit(1);
}
return mode;
}
static void setConsoleMode(DWORD mode) {
if (!SetConsoleMode(getConin(), mode)) {
fprintf(stderr, "error: SetConsoleMode failed (is stdin a console?)\n");
exit(1);
}
}
static long parseInt(const std::string &s) {
errno = 0;
char *endptr = nullptr;
long result = strtol(s.c_str(), &endptr, 0);
if (errno != 0 || !endptr || *endptr != '\0') {
fprintf(stderr, "error: could not parse integral argument '%s'\n", s.c_str());
exit(1);
}
return result;
}
static void usage() {
printf("Usage: ConinMode [verb] [options]\n");
printf("Verbs:\n");
printf(" [info] Dumps info about mode flags.\n");
printf(" get Prints the mode DWORD.\n");
printf(" set VALUE Sets the mode to VALUE, which can be decimal, hex, or octal.\n");
printf(" set VALUE MASK\n");
printf(" Same as `set VALUE`, but only alters the bits in MASK.\n");
exit(1);
}
struct {
const char *name;
DWORD value;
} kInputFlags[] = {
"ENABLE_PROCESSED_INPUT", ENABLE_PROCESSED_INPUT, // 0x0001
"ENABLE_LINE_INPUT", ENABLE_LINE_INPUT, // 0x0002
"ENABLE_ECHO_INPUT", ENABLE_ECHO_INPUT, // 0x0004
"ENABLE_WINDOW_INPUT", ENABLE_WINDOW_INPUT, // 0x0008
"ENABLE_MOUSE_INPUT", ENABLE_MOUSE_INPUT, // 0x0010
"ENABLE_INSERT_MODE", ENABLE_INSERT_MODE, // 0x0020
"ENABLE_QUICK_EDIT_MODE", ENABLE_QUICK_EDIT_MODE, // 0x0040
"ENABLE_EXTENDED_FLAGS", ENABLE_EXTENDED_FLAGS, // 0x0080
"ENABLE_VIRTUAL_TERMINAL_INPUT", 0x0200/*ENABLE_VIRTUAL_TERMINAL_INPUT*/, // 0x0200
};
int main(int argc, char *argv[]) {
std::vector<std::string> args;
for (size_t i = 1; i < argc; ++i) {
args.push_back(argv[i]);
}
if (args.empty() || args.size() == 1 && args[0] == "info") {
DWORD mode = getConsoleMode();
printf("mode: 0x%lx\n", mode);
for (const auto &flag : kInputFlags) {
printf("%-29s 0x%04lx %s\n", flag.name, flag.value, flag.value & mode ? "ON" : "off");
mode &= ~flag.value;
}
for (int i = 0; i < 32; ++i) {
if (mode & (1u << i)) {
printf("Unrecognized flag: %04x\n", (1u << i));
}
}
return 0;
}
const auto verb = args[0];
if (verb == "set") {
if (args.size() == 2) {
const DWORD newMode = parseInt(args[1]);
setConsoleMode(newMode);
} else if (args.size() == 3) {
const DWORD mode = parseInt(args[1]);
const DWORD mask = parseInt(args[2]);
const int newMode = (getConsoleMode() & ~mask) | (mode & mask);
setConsoleMode(newMode);
} else {
usage();
}
} else if (verb == "get") {
if (args.size() != 1) {
usage();
}
printf("0x%lx\n", getConsoleMode());
} else {
usage();
}
return 0;
}

View File

@@ -0,0 +1,116 @@
#
# PowerShell script for controlling the console QuickEdit and InsertMode flags.
#
# Turn QuickEdit off to interact with mouse-driven console programs.
#
# Usage:
#
# powershell .\ConinMode.ps1 [Options]
#
# Options:
# -QuickEdit [on/off]
# -InsertMode [on/off]
# -Mode [integer]
#
param (
[ValidateSet("on", "off")][string] $QuickEdit,
[ValidateSet("on", "off")][string] $InsertMode,
[int] $Mode
)
$signature = @'
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint GetConsoleMode(
IntPtr hConsoleHandle,
out uint lpMode);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint SetConsoleMode(
IntPtr hConsoleHandle,
uint dwMode);
public const int STD_INPUT_HANDLE = -10;
public const int ENABLE_INSERT_MODE = 0x0020;
public const int ENABLE_QUICK_EDIT_MODE = 0x0040;
public const int ENABLE_EXTENDED_FLAGS = 0x0080;
'@
$WinAPI = Add-Type -MemberDefinition $signature `
-Name WinAPI -Namespace ConinModeScript `
-PassThru
function GetConIn {
$ret = $WinAPI::GetStdHandle($WinAPI::STD_INPUT_HANDLE)
if ($ret -eq -1) {
throw "error: cannot get stdin"
}
return $ret
}
function GetConsoleMode {
$conin = GetConIn
$mode = 0
$ret = $WinAPI::GetConsoleMode($conin, [ref]$mode)
if ($ret -eq 0) {
throw "GetConsoleMode failed (is stdin a console?)"
}
return $mode
}
function SetConsoleMode($mode) {
$conin = GetConIn
$ret = $WinAPI::SetConsoleMode($conin, $mode)
if ($ret -eq 0) {
throw "SetConsoleMode failed (is stdin a console?)"
}
}
$oldMode = GetConsoleMode
$newMode = $oldMode
$doingSomething = $false
if ($PSBoundParameters.ContainsKey("Mode")) {
$newMode = $Mode
$doingSomething = $true
}
if ($QuickEdit + $InsertMode -ne "") {
if (!($newMode -band $WinAPI::ENABLE_EXTENDED_FLAGS)) {
# We can't enable an extended flag without overwriting the existing
# QuickEdit/InsertMode flags. AFAICT, there is no way to query their
# existing values, so at least we can choose sensible defaults.
$newMode = $newMode -bor $WinAPI::ENABLE_EXTENDED_FLAGS
$newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE
$newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE
$doingSomething = $true
}
}
if ($QuickEdit -eq "on") {
$newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE
$doingSomething = $true
} elseif ($QuickEdit -eq "off") {
$newMode = $newMode -band (-bnot $WinAPI::ENABLE_QUICK_EDIT_MODE)
$doingSomething = $true
}
if ($InsertMode -eq "on") {
$newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE
$doingSomething = $true
} elseif ($InsertMode -eq "off") {
$newMode = $newMode -band (-bnot $WinAPI::ENABLE_INSERT_MODE)
$doingSomething = $true
}
if ($doingSomething) {
echo "old mode: $oldMode"
SetConsoleMode $newMode
$newMode = GetConsoleMode
echo "new mode: $newMode"
} else {
echo "mode: $oldMode"
}

View File

@@ -0,0 +1,113 @@
#include <windows.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
static HANDLE getConout() {
HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
if (conout == INVALID_HANDLE_VALUE) {
fprintf(stderr, "error: cannot get stdout\n");
exit(1);
}
return conout;
}
static DWORD getConsoleMode() {
DWORD mode = 0;
if (!GetConsoleMode(getConout(), &mode)) {
fprintf(stderr, "error: GetConsoleMode failed (is stdout a console?)\n");
exit(1);
}
return mode;
}
static void setConsoleMode(DWORD mode) {
if (!SetConsoleMode(getConout(), mode)) {
fprintf(stderr, "error: SetConsoleMode failed (is stdout a console?)\n");
exit(1);
}
}
static long parseInt(const std::string &s) {
errno = 0;
char *endptr = nullptr;
long result = strtol(s.c_str(), &endptr, 0);
if (errno != 0 || !endptr || *endptr != '\0') {
fprintf(stderr, "error: could not parse integral argument '%s'\n", s.c_str());
exit(1);
}
return result;
}
static void usage() {
printf("Usage: ConoutMode [verb] [options]\n");
printf("Verbs:\n");
printf(" [info] Dumps info about mode flags.\n");
printf(" get Prints the mode DWORD.\n");
printf(" set VALUE Sets the mode to VALUE, which can be decimal, hex, or octal.\n");
printf(" set VALUE MASK\n");
printf(" Same as `set VALUE`, but only alters the bits in MASK.\n");
exit(1);
}
struct {
const char *name;
DWORD value;
} kOutputFlags[] = {
"ENABLE_PROCESSED_OUTPUT", ENABLE_PROCESSED_OUTPUT, // 0x0001
"ENABLE_WRAP_AT_EOL_OUTPUT", ENABLE_WRAP_AT_EOL_OUTPUT, // 0x0002
"ENABLE_VIRTUAL_TERMINAL_PROCESSING", 0x0004/*ENABLE_VIRTUAL_TERMINAL_PROCESSING*/, // 0x0004
"DISABLE_NEWLINE_AUTO_RETURN", 0x0008/*DISABLE_NEWLINE_AUTO_RETURN*/, // 0x0008
"ENABLE_LVB_GRID_WORLDWIDE", 0x0010/*ENABLE_LVB_GRID_WORLDWIDE*/, //0x0010
};
int main(int argc, char *argv[]) {
std::vector<std::string> args;
for (size_t i = 1; i < argc; ++i) {
args.push_back(argv[i]);
}
if (args.empty() || args.size() == 1 && args[0] == "info") {
DWORD mode = getConsoleMode();
printf("mode: 0x%lx\n", mode);
for (const auto &flag : kOutputFlags) {
printf("%-34s 0x%04lx %s\n", flag.name, flag.value, flag.value & mode ? "ON" : "off");
mode &= ~flag.value;
}
for (int i = 0; i < 32; ++i) {
if (mode & (1u << i)) {
printf("Unrecognized flag: %04x\n", (1u << i));
}
}
return 0;
}
const auto verb = args[0];
if (verb == "set") {
if (args.size() == 2) {
const DWORD newMode = parseInt(args[1]);
setConsoleMode(newMode);
} else if (args.size() == 3) {
const DWORD mode = parseInt(args[1]);
const DWORD mask = parseInt(args[2]);
const int newMode = (getConsoleMode() & ~mask) | (mode & mask);
setConsoleMode(newMode);
} else {
usage();
}
} else if (verb == "get") {
if (args.size() != 1) {
usage();
}
printf("0x%lx\n", getConsoleMode());
} else {
usage();
}
return 0;
}

View File

@@ -0,0 +1,42 @@
#!python
# Run with native CPython. Needs pywin32 extensions.
# Copyright (c) 2011-2012 Ryan Prichard
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
import winerror
import win32pipe
import win32file
import win32api
import sys
import pywintypes
import time
if len(sys.argv) != 2:
print("Usage: %s message" % sys.argv[0])
sys.exit(1)
message = "[%05.3f %s]: %s" % (time.time() % 100000, sys.argv[0], sys.argv[1])
win32pipe.CallNamedPipe(
"\\\\.\\pipe\\DebugServer",
message.encode(),
16,
win32pipe.NMPWAIT_WAIT_FOREVER)

View File

@@ -0,0 +1,63 @@
#!python
#
# Run with native CPython. Needs pywin32 extensions.
# Copyright (c) 2011-2012 Ryan Prichard
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
import win32pipe
import win32api
import win32file
import time
import threading
import sys
# A message may not be larger than this size.
MSG_SIZE=4096
serverPipe = win32pipe.CreateNamedPipe(
"\\\\.\\pipe\\DebugServer",
win32pipe.PIPE_ACCESS_DUPLEX,
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE,
win32pipe.PIPE_UNLIMITED_INSTANCES,
MSG_SIZE,
MSG_SIZE,
10 * 1000,
None)
while True:
win32pipe.ConnectNamedPipe(serverPipe, None)
(ret, data) = win32file.ReadFile(serverPipe, MSG_SIZE)
print(data.decode())
sys.stdout.flush()
# The client uses CallNamedPipe to send its message. CallNamedPipe waits
# for a reply message. If I send a reply, however, using WriteFile, then
# sometimes WriteFile fails with:
# pywintypes.error: (232, 'WriteFile', 'The pipe is being closed.')
# I can't figure out how to write a strictly correct pipe server, but if
# I comment out the WriteFile line, then everything seems to work. I
# think the DisconnectNamedPipe call aborts the client's CallNamedPipe
# call normally.
try:
win32file.WriteFile(serverPipe, b'OK')
except:
pass
win32pipe.DisconnectNamedPipe(serverPipe)

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env python
import sys
for i in range(1, int(sys.argv[1]) + 1):
print i, "X" * 78

View File

@@ -0,0 +1,46 @@
Note regarding ENABLE_EXTENDED_FLAGS (2016-05-30)
There is a complicated interaction between the ENABLE_EXTENDED_FLAGS flag
and the ENABLE_QUICK_EDIT_MODE and ENABLE_INSERT_MODE flags (presumably for
backwards compatibility?). I studied the behavior on Windows 7 and Windows
10, with both the old and new consoles, and I didn't see any differences
between versions. Here's what I seemed to observe:
- The console has three flags internally:
- QuickEdit
- InsertMode
- ExtendedFlags
- SetConsoleMode psuedocode:
void SetConsoleMode(..., DWORD mode) {
ExtendedFlags = (mode & (ENABLE_EXTENDED_FLAGS
| ENABLE_QUICK_EDIT_MODE
| ENABLE_INSERT_MODE )) != 0;
if (ExtendedFlags) {
QuickEdit = (mode & ENABLE_QUICK_EDIT_MODE) != 0;
InsertMode = (mode & ENABLE_INSERT_MODE) != 0;
}
}
- Setting QuickEdit or InsertMode from the properties dialog GUI does not
affect the ExtendedFlags setting -- it simply toggles the one flag.
- GetConsoleMode psuedocode:
GetConsoleMode(..., DWORD *result) {
if (ExtendedFlags) {
*result |= ENABLE_EXTENDED_FLAGS;
if (QuickEdit) { *result |= ENABLE_QUICK_EDIT_MODE; }
if (InsertMode) { *result |= ENABLE_INSERT_MODE; }
}
}
Effectively, the ExtendedFlags flags controls whether the other two flags
are visible/controlled by the user application. If they aren't visible,
though, there is no way for the user application to make them visible,
except by overwriting their values! Calling SetConsoleMode with just
ENABLE_EXTENDED_FLAGS would clear the extended flags we want to read.
Consequently, if a program temporarily alters the QuickEdit flag (e.g. to
enable mouse input), it cannot restore the original values of the QuickEdit
and InsertMode flags, UNLESS every other console program cooperates by
keeping the ExtendedFlags flag set.

View File

@@ -0,0 +1,528 @@
==================================
Code Page 437, Consolas font
==================================
Options: -face "Consolas" -family 0x36
Chars: A2 A3 2014 3044 30FC 4000
FontSurvey "-face \"Consolas\" -family 0x36"
Windows 7
---------
Size 1: 1,3 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 1,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 2,5 BAD (HHHHHH)
Size 6: 3,6 BAD (HHHHHH)
Size 7: 3,6 BAD (HHHHHH)
Size 8: 4,8 BAD (HHHHHH)
Size 9: 4,9 BAD (HHHHHH)
Size 10: 5,10 BAD (HHHHHH)
Size 11: 5,11 BAD (HHHHHH)
Size 12: 6,12 BAD (HHHHHH)
Size 13: 6,13 BAD (HHHHHH)
Size 14: 7,14 BAD (HHHHHH)
Size 15: 7,15 BAD (HHHHHH)
Size 16: 8,16 BAD (HHHHHH)
Size 17: 8,17 BAD (HHHHHH)
Size 18: 8,18 BAD (HHHHHH)
Size 19: 9,19 BAD (HHHHHH)
Size 20: 9,20 BAD (HHHHHH)
Size 21: 10,22 BAD (HHHHHH)
Size 22: 10,22 BAD (HHHHHH)
Size 23: 11,23 BAD (HHHHHH)
Size 24: 11,24 BAD (HHHHHH)
Size 25: 12,25 BAD (HHHHHH)
Size 26: 12,26 BAD (HHHHHH)
Size 27: 13,27 BAD (HHHHHH)
Size 28: 13,28 BAD (HHHHHH)
Size 29: 14,29 BAD (HHHHHH)
Size 30: 14,30 BAD (HHHHHH)
Size 31: 15,31 BAD (HHHHHH)
Size 32: 15,32 BAD (HHHHHH)
Size 33: 15,33 BAD (HHHHHH)
Size 34: 16,34 BAD (HHHHHH)
Size 35: 16,36 BAD (HHHHHH)
Size 36: 17,36 BAD (HHHHHH)
Size 37: 17,37 BAD (HHHHHH)
Size 38: 18,38 BAD (HHHHHH)
Size 39: 18,39 BAD (HHHHHH)
Size 40: 19,40 BAD (HHHHHH)
Size 41: 19,41 BAD (HHHHHH)
Size 42: 20,42 BAD (HHHHHH)
Size 43: 20,43 BAD (HHHHHH)
Size 44: 21,44 BAD (HHHHHH)
Size 45: 21,45 BAD (HHHHHH)
Size 46: 22,46 BAD (HHHHHH)
Size 47: 22,47 BAD (HHHHHH)
Size 48: 23,48 BAD (HHHHHH)
Size 49: 23,49 BAD (HHHHHH)
Size 50: 23,50 BAD (HHHHHH)
Size 51: 24,51 BAD (HHHHHH)
Size 52: 24,52 BAD (HHHHHH)
Size 53: 25,53 BAD (HHHHHH)
Size 54: 25,54 BAD (HHHHHH)
Size 55: 26,55 BAD (HHHHHH)
Size 56: 26,56 BAD (HHHHHH)
Size 57: 27,57 BAD (HHHHHH)
Size 58: 27,58 BAD (HHHHHH)
Size 59: 28,59 BAD (HHHHHH)
Size 60: 28,60 BAD (HHHHHH)
Size 61: 29,61 BAD (HHHHHH)
Size 62: 29,62 BAD (HHHHHH)
Size 63: 30,64 BAD (HHHHHH)
Size 64: 30,64 BAD (HHHHHH)
Size 65: 31,65 BAD (HHHHHH)
Size 66: 31,66 BAD (HHHHHH)
Size 67: 31,67 BAD (HHHHHH)
Size 68: 32,68 BAD (HHHHHH)
Size 69: 32,69 BAD (HHHHHH)
Size 70: 33,70 BAD (HHHHHH)
Size 71: 33,71 BAD (HHHHHH)
Size 72: 34,72 BAD (HHHHHH)
Size 73: 34,73 BAD (HHHHHH)
Size 74: 35,74 BAD (HHHHHH)
Size 75: 35,75 BAD (HHHHHH)
Size 76: 36,76 BAD (HHHHHH)
Size 77: 36,77 BAD (HHHHHH)
Size 78: 37,78 BAD (HHHHHH)
Size 79: 37,79 BAD (HHHHHH)
Size 80: 38,80 BAD (HHHHHH)
Size 81: 38,81 BAD (HHHHHH)
Size 82: 39,82 BAD (HHHHHH)
Size 83: 39,83 BAD (HHHHHH)
Size 84: 39,84 BAD (HHHHHH)
Size 85: 40,85 BAD (HHHHHH)
Size 86: 40,86 BAD (HHHHHH)
Size 87: 41,87 BAD (HHHHHH)
Size 88: 41,88 BAD (HHHHHH)
Size 89: 42,89 BAD (HHHHHH)
Size 90: 42,90 BAD (HHHHHH)
Size 91: 43,91 BAD (HHHHHH)
Size 92: 43,92 BAD (HHHHHH)
Size 93: 44,93 BAD (HHHHHH)
Size 94: 44,94 BAD (HHHHHH)
Size 95: 45,95 BAD (HHHHHH)
Size 96: 45,96 BAD (HHHHHH)
Size 97: 46,97 BAD (HHHHHH)
Size 98: 46,98 BAD (HHHHHH)
Size 99: 46,99 BAD (HHHHHH)
Size 100: 47,100 BAD (HHHHHH)
Windows 8
---------
Size 1: 1,3 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 1,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 2,5 BAD (HHHHHH)
Size 6: 3,6 BAD (HHHHHH)
Size 7: 3,6 BAD (HHHHHH)
Size 8: 4,8 BAD (HHHHHH)
Size 9: 4,9 BAD (HHHHHH)
Size 10: 5,10 BAD (HHHHHH)
Size 11: 5,11 BAD (HHHHHH)
Size 12: 6,12 BAD (HHHHHH)
Size 13: 6,13 BAD (HHHHHH)
Size 14: 7,14 BAD (HHHHHH)
Size 15: 7,15 BAD (HHHHHH)
Size 16: 8,16 BAD (HHHHHH)
Size 17: 8,17 BAD (HHHHHH)
Size 18: 8,18 BAD (HHHHHH)
Size 19: 9,19 BAD (HHHHHH)
Size 20: 9,20 BAD (HHHHHH)
Size 21: 10,22 BAD (HHHHHH)
Size 22: 10,22 BAD (HHHHHH)
Size 23: 11,23 BAD (HHHHHH)
Size 24: 11,24 BAD (HHHHHH)
Size 25: 12,25 BAD (HHHHHH)
Size 26: 12,26 BAD (HHHHHH)
Size 27: 13,27 BAD (HHHHHH)
Size 28: 13,28 BAD (HHHHHH)
Size 29: 14,29 BAD (HHHHHH)
Size 30: 14,30 BAD (HHHHHH)
Size 31: 15,31 BAD (HHHHHH)
Size 32: 15,32 BAD (HHHHHH)
Size 33: 15,33 BAD (HHHHHH)
Size 34: 16,34 BAD (HHHHHH)
Size 35: 16,36 BAD (HHHHHH)
Size 36: 17,36 BAD (HHHHHH)
Size 37: 17,37 BAD (HHHHHH)
Size 38: 18,38 BAD (HHHHHH)
Size 39: 18,39 BAD (HHHHHH)
Size 40: 19,40 BAD (HHHHHH)
Size 41: 19,41 BAD (HHHHHH)
Size 42: 20,42 BAD (HHHHHH)
Size 43: 20,43 BAD (HHHHHH)
Size 44: 21,44 BAD (HHHHHH)
Size 45: 21,45 BAD (HHHHHH)
Size 46: 22,46 BAD (HHHHHH)
Size 47: 22,47 BAD (HHHHHH)
Size 48: 23,48 BAD (HHHHHH)
Size 49: 23,49 BAD (HHHHHH)
Size 50: 23,50 BAD (HHHHHH)
Size 51: 24,51 BAD (HHHHHH)
Size 52: 24,52 BAD (HHHHHH)
Size 53: 25,53 BAD (HHHHHH)
Size 54: 25,54 BAD (HHHHHH)
Size 55: 26,55 BAD (HHHHHH)
Size 56: 26,56 BAD (HHHHHH)
Size 57: 27,57 BAD (HHHHHH)
Size 58: 27,58 BAD (HHHHHH)
Size 59: 28,59 BAD (HHHHHH)
Size 60: 28,60 BAD (HHHHHH)
Size 61: 29,61 BAD (HHHHHH)
Size 62: 29,62 BAD (HHHHHH)
Size 63: 30,64 BAD (HHHHHH)
Size 64: 30,64 BAD (HHHHHH)
Size 65: 31,65 BAD (HHHHHH)
Size 66: 31,66 BAD (HHHHHH)
Size 67: 31,67 BAD (HHHHHH)
Size 68: 32,68 BAD (HHHHHH)
Size 69: 32,69 BAD (HHHHHH)
Size 70: 33,70 BAD (HHHHHH)
Size 71: 33,71 BAD (HHHHHH)
Size 72: 34,72 BAD (HHHHHH)
Size 73: 34,73 BAD (HHHHHH)
Size 74: 35,74 BAD (HHHHHH)
Size 75: 35,75 BAD (HHHHHH)
Size 76: 36,76 BAD (HHHHHH)
Size 77: 36,77 BAD (HHHHHH)
Size 78: 37,78 BAD (HHHHHH)
Size 79: 37,79 BAD (HHHHHH)
Size 80: 38,80 BAD (HHHHHH)
Size 81: 38,81 BAD (HHHHHH)
Size 82: 39,82 BAD (HHHHHH)
Size 83: 39,83 BAD (HHHHHH)
Size 84: 39,84 BAD (HHHHHH)
Size 85: 40,85 BAD (HHHHHH)
Size 86: 40,86 BAD (HHHHHH)
Size 87: 41,87 BAD (HHHHHH)
Size 88: 41,88 BAD (HHHHHH)
Size 89: 42,89 BAD (HHHHHH)
Size 90: 42,90 BAD (HHHHHH)
Size 91: 43,91 BAD (HHHHHH)
Size 92: 43,92 BAD (HHHHHH)
Size 93: 44,93 BAD (HHHHHH)
Size 94: 44,94 BAD (HHHHHH)
Size 95: 45,95 BAD (HHHHHH)
Size 96: 45,96 BAD (HHHHHH)
Size 97: 46,97 BAD (HHHHHH)
Size 98: 46,98 BAD (HHHHHH)
Size 99: 46,99 BAD (HHHHHH)
Size 100: 47,100 BAD (HHHHHH)
Windows 8.1
-----------
Size 1: 1,3 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 1,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 2,5 BAD (HHHHHH)
Size 6: 3,6 BAD (HHHHHH)
Size 7: 3,6 BAD (HHHHHH)
Size 8: 4,8 BAD (HHHHHH)
Size 9: 4,9 BAD (HHHHHH)
Size 10: 5,10 BAD (HHHHHH)
Size 11: 5,11 BAD (HHHHHH)
Size 12: 6,12 BAD (HHHHHH)
Size 13: 6,13 BAD (HHHHHH)
Size 14: 7,14 BAD (HHHHHH)
Size 15: 7,15 BAD (HHHHHH)
Size 16: 8,16 BAD (HHHHHH)
Size 17: 8,17 BAD (HHHHHH)
Size 18: 8,18 BAD (HHHHHH)
Size 19: 9,19 BAD (HHHHHH)
Size 20: 9,20 BAD (HHHHHH)
Size 21: 10,22 BAD (HHHHHH)
Size 22: 10,22 BAD (HHHHHH)
Size 23: 11,23 BAD (HHHHHH)
Size 24: 11,24 BAD (HHHHHH)
Size 25: 12,25 BAD (HHHHHH)
Size 26: 12,26 BAD (HHHHHH)
Size 27: 13,27 BAD (HHHHHH)
Size 28: 13,28 BAD (HHHHHH)
Size 29: 14,29 BAD (HHHHHH)
Size 30: 14,30 BAD (HHHHHH)
Size 31: 15,31 BAD (HHHHHH)
Size 32: 15,32 BAD (HHHHHH)
Size 33: 15,33 BAD (HHHHHH)
Size 34: 16,34 BAD (HHHHHH)
Size 35: 16,36 BAD (HHHHHH)
Size 36: 17,36 BAD (HHHHHH)
Size 37: 17,37 BAD (HHHHHH)
Size 38: 18,38 BAD (HHHHHH)
Size 39: 18,39 BAD (HHHHHH)
Size 40: 19,40 BAD (HHHHHH)
Size 41: 19,41 BAD (HHHHHH)
Size 42: 20,42 BAD (HHHHHH)
Size 43: 20,43 BAD (HHHHHH)
Size 44: 21,44 BAD (HHHHHH)
Size 45: 21,45 BAD (HHHHHH)
Size 46: 22,46 BAD (HHHHHH)
Size 47: 22,47 BAD (HHHHHH)
Size 48: 23,48 BAD (HHHHHH)
Size 49: 23,49 BAD (HHHHHH)
Size 50: 23,50 BAD (HHHHHH)
Size 51: 24,51 BAD (HHHHHH)
Size 52: 24,52 BAD (HHHHHH)
Size 53: 25,53 BAD (HHHHHH)
Size 54: 25,54 BAD (HHHHHH)
Size 55: 26,55 BAD (HHHHHH)
Size 56: 26,56 BAD (HHHHHH)
Size 57: 27,57 BAD (HHHHHH)
Size 58: 27,58 BAD (HHHHHH)
Size 59: 28,59 BAD (HHHHHH)
Size 60: 28,60 BAD (HHHHHH)
Size 61: 29,61 BAD (HHHHHH)
Size 62: 29,62 BAD (HHHHHH)
Size 63: 30,64 BAD (HHHHHH)
Size 64: 30,64 BAD (HHHHHH)
Size 65: 31,65 BAD (HHHHHH)
Size 66: 31,66 BAD (HHHHHH)
Size 67: 31,67 BAD (HHHHHH)
Size 68: 32,68 BAD (HHHHHH)
Size 69: 32,69 BAD (HHHHHH)
Size 70: 33,70 BAD (HHHHHH)
Size 71: 33,71 BAD (HHHHHH)
Size 72: 34,72 BAD (HHHHHH)
Size 73: 34,73 BAD (HHHHHH)
Size 74: 35,74 BAD (HHHHHH)
Size 75: 35,75 BAD (HHHHHH)
Size 76: 36,76 BAD (HHHHHH)
Size 77: 36,77 BAD (HHHHHH)
Size 78: 37,78 BAD (HHHHHH)
Size 79: 37,79 BAD (HHHHHH)
Size 80: 38,80 BAD (HHHHHH)
Size 81: 38,81 BAD (HHHHHH)
Size 82: 39,82 BAD (HHHHHH)
Size 83: 39,83 BAD (HHHHHH)
Size 84: 39,84 BAD (HHHHHH)
Size 85: 40,85 BAD (HHHHHH)
Size 86: 40,86 BAD (HHHHHH)
Size 87: 41,87 BAD (HHHHHH)
Size 88: 41,88 BAD (HHHHHH)
Size 89: 42,89 BAD (HHHHHH)
Size 90: 42,90 BAD (HHHHHH)
Size 91: 43,91 BAD (HHHHHH)
Size 92: 43,92 BAD (HHHHHH)
Size 93: 44,93 BAD (HHHHHH)
Size 94: 44,94 BAD (HHHHHH)
Size 95: 45,95 BAD (HHHHHH)
Size 96: 45,96 BAD (HHHHHH)
Size 97: 46,97 BAD (HHHHHH)
Size 98: 46,98 BAD (HHHHHH)
Size 99: 46,99 BAD (HHHHHH)
Size 100: 47,100 BAD (HHHHHH)
Windows 10 14342 Old Console
----------------------------
Size 1: 1,3 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 1,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 2,5 BAD (HHHHHH)
Size 6: 3,6 BAD (HHHHHH)
Size 7: 3,6 BAD (HHHHHH)
Size 8: 4,8 BAD (HHHHHH)
Size 9: 4,9 BAD (HHHHHH)
Size 10: 5,10 BAD (HHHHHH)
Size 11: 5,11 BAD (HHHHHH)
Size 12: 6,12 BAD (HHHHHH)
Size 13: 6,13 BAD (HHHHHH)
Size 14: 7,14 BAD (HHHHHH)
Size 15: 7,15 BAD (HHHHHH)
Size 16: 8,16 BAD (HHHHHH)
Size 17: 8,17 BAD (HHHHHH)
Size 18: 8,18 BAD (HHHHHH)
Size 19: 9,19 BAD (HHHHHH)
Size 20: 9,20 BAD (HHHHHH)
Size 21: 10,22 BAD (HHHHHH)
Size 22: 10,22 BAD (HHHHHH)
Size 23: 11,23 BAD (HHHHHH)
Size 24: 11,24 BAD (HHHHHH)
Size 25: 12,25 BAD (HHHHHH)
Size 26: 12,26 BAD (HHHHHH)
Size 27: 13,27 BAD (HHHHHH)
Size 28: 13,28 BAD (HHHHHH)
Size 29: 14,29 BAD (HHHHHH)
Size 30: 14,30 BAD (HHHHHH)
Size 31: 15,31 BAD (HHHHHH)
Size 32: 15,32 BAD (HHHHHH)
Size 33: 15,33 BAD (HHHHHH)
Size 34: 16,34 BAD (HHHHHH)
Size 35: 16,36 BAD (HHHHHH)
Size 36: 17,36 BAD (HHHHHH)
Size 37: 17,37 BAD (HHHHHH)
Size 38: 18,38 BAD (HHHHHH)
Size 39: 18,39 BAD (HHHHHH)
Size 40: 19,40 BAD (HHHHHH)
Size 41: 19,41 BAD (HHHHHH)
Size 42: 20,42 BAD (HHHHHH)
Size 43: 20,43 BAD (HHHHHH)
Size 44: 21,44 BAD (HHHHHH)
Size 45: 21,45 BAD (HHHHHH)
Size 46: 22,46 BAD (HHHHHH)
Size 47: 22,47 BAD (HHHHHH)
Size 48: 23,48 BAD (HHHHHH)
Size 49: 23,49 BAD (HHHHHH)
Size 50: 23,50 BAD (HHHHHH)
Size 51: 24,51 BAD (HHHHHH)
Size 52: 24,52 BAD (HHHHHH)
Size 53: 25,53 BAD (HHHHHH)
Size 54: 25,54 BAD (HHHHHH)
Size 55: 26,55 BAD (HHHHHH)
Size 56: 26,56 BAD (HHHHHH)
Size 57: 27,57 BAD (HHHHHH)
Size 58: 27,58 BAD (HHHHHH)
Size 59: 28,59 BAD (HHHHHH)
Size 60: 28,60 BAD (HHHHHH)
Size 61: 29,61 BAD (HHHHHH)
Size 62: 29,62 BAD (HHHHHH)
Size 63: 30,64 BAD (HHHHHH)
Size 64: 30,64 BAD (HHHHHH)
Size 65: 31,65 BAD (HHHHHH)
Size 66: 31,66 BAD (HHHHHH)
Size 67: 31,67 BAD (HHHHHH)
Size 68: 32,68 BAD (HHHHHH)
Size 69: 32,69 BAD (HHHHHH)
Size 70: 33,70 BAD (HHHHHH)
Size 71: 33,71 BAD (HHHHHH)
Size 72: 34,72 BAD (HHHHHH)
Size 73: 34,73 BAD (HHHHHH)
Size 74: 35,74 BAD (HHHHHH)
Size 75: 35,75 BAD (HHHHHH)
Size 76: 36,76 BAD (HHHHHH)
Size 77: 36,77 BAD (HHHHHH)
Size 78: 37,78 BAD (HHHHHH)
Size 79: 37,79 BAD (HHHHHH)
Size 80: 38,80 BAD (HHHHHH)
Size 81: 38,81 BAD (HHHHHH)
Size 82: 39,82 BAD (HHHHHH)
Size 83: 39,83 BAD (HHHHHH)
Size 84: 39,84 BAD (HHHHHH)
Size 85: 40,85 BAD (HHHHHH)
Size 86: 40,86 BAD (HHHHHH)
Size 87: 41,87 BAD (HHHHHH)
Size 88: 41,88 BAD (HHHHHH)
Size 89: 42,89 BAD (HHHHHH)
Size 90: 42,90 BAD (HHHHHH)
Size 91: 43,91 BAD (HHHHHH)
Size 92: 43,92 BAD (HHHHHH)
Size 93: 44,93 BAD (HHHHHH)
Size 94: 44,94 BAD (HHHHHH)
Size 95: 45,95 BAD (HHHHHH)
Size 96: 45,96 BAD (HHHHHH)
Size 97: 46,97 BAD (HHHHHH)
Size 98: 46,98 BAD (HHHHHH)
Size 99: 46,99 BAD (HHHHHH)
Size 100: 47,100 BAD (HHHHHH)
Windows 10 14342 New Console
----------------------------
Size 1: 1,1 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 1,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 2,5 BAD (HHHHHH)
Size 6: 3,6 BAD (HHHHHH)
Size 7: 3,7 BAD (HHHHHH)
Size 8: 4,8 BAD (HHHHHH)
Size 9: 4,9 BAD (HHHHHH)
Size 10: 5,10 BAD (HHHHHH)
Size 11: 5,11 BAD (HHHHHH)
Size 12: 6,12 BAD (HHHHHH)
Size 13: 6,13 BAD (HHHHHH)
Size 14: 7,14 BAD (HHHHHH)
Size 15: 7,15 BAD (HHHHHH)
Size 16: 8,16 BAD (HHHHHH)
Size 17: 8,17 BAD (HHHHHH)
Size 18: 8,18 BAD (HHHHHH)
Size 19: 9,19 BAD (HHHHHH)
Size 20: 9,20 BAD (HHHHHH)
Size 21: 10,21 BAD (HHHHHH)
Size 22: 10,22 BAD (HHHHHH)
Size 23: 11,23 BAD (HHHHHH)
Size 24: 11,24 BAD (HHHHHH)
Size 25: 12,25 BAD (HHHHHH)
Size 26: 12,26 BAD (HHHHHH)
Size 27: 13,27 BAD (HHHHHH)
Size 28: 13,28 BAD (HHHHHH)
Size 29: 14,29 BAD (HHHHHH)
Size 30: 14,30 BAD (HHHHHH)
Size 31: 15,31 BAD (HHHHHH)
Size 32: 15,32 BAD (HHHHHH)
Size 33: 15,33 BAD (HHHHHH)
Size 34: 16,34 BAD (HHHHHH)
Size 35: 16,35 BAD (HHHHHH)
Size 36: 17,36 BAD (HHHHHH)
Size 37: 17,37 BAD (HHHHHH)
Size 38: 18,38 BAD (HHHHHH)
Size 39: 18,39 BAD (HHHHHH)
Size 40: 19,40 BAD (HHHHHH)
Size 41: 19,41 BAD (HHHHHH)
Size 42: 20,42 BAD (HHHHHH)
Size 43: 20,43 BAD (HHHHHH)
Size 44: 21,44 BAD (HHHHHH)
Size 45: 21,45 BAD (HHHHHH)
Size 46: 22,46 BAD (HHHHHH)
Size 47: 22,47 BAD (HHHHHH)
Size 48: 23,48 BAD (HHHHHH)
Size 49: 23,49 BAD (HHHHHH)
Size 50: 23,50 BAD (HHHHHH)
Size 51: 24,51 BAD (HHHHHH)
Size 52: 24,52 BAD (HHHHHH)
Size 53: 25,53 BAD (HHHHHH)
Size 54: 25,54 BAD (HHHHHH)
Size 55: 26,55 BAD (HHHHHH)
Size 56: 26,56 BAD (HHHHHH)
Size 57: 27,57 BAD (HHHHHH)
Size 58: 27,58 BAD (HHHHHH)
Size 59: 28,59 BAD (HHHHHH)
Size 60: 28,60 BAD (HHHHHH)
Size 61: 29,61 BAD (HHHHHH)
Size 62: 29,62 BAD (HHHHHH)
Size 63: 30,63 BAD (HHHHHH)
Size 64: 30,64 BAD (HHHHHH)
Size 65: 31,65 BAD (HHHHHH)
Size 66: 31,66 BAD (HHHHHH)
Size 67: 31,67 BAD (HHHHHH)
Size 68: 32,68 BAD (HHHHHH)
Size 69: 32,69 BAD (HHHHHH)
Size 70: 33,70 BAD (HHHHHH)
Size 71: 33,71 BAD (HHHHHH)
Size 72: 34,72 BAD (HHHHHH)
Size 73: 34,73 BAD (HHHHHH)
Size 74: 35,74 BAD (HHHHHH)
Size 75: 35,75 BAD (HHHHHH)
Size 76: 36,76 BAD (HHHHHH)
Size 77: 36,77 BAD (HHHHHH)
Size 78: 37,78 BAD (HHHHHH)
Size 79: 37,79 BAD (HHHHHH)
Size 80: 38,80 BAD (HHHHHH)
Size 81: 38,81 BAD (HHHHHH)
Size 82: 39,82 BAD (HHHHHH)
Size 83: 39,83 BAD (HHHHHH)
Size 84: 39,84 BAD (HHHHHH)
Size 85: 40,85 BAD (HHHHHH)
Size 86: 40,86 BAD (HHHHHH)
Size 87: 41,87 BAD (HHHHHH)
Size 88: 41,88 BAD (HHHHHH)
Size 89: 42,89 BAD (HHHHHH)
Size 90: 42,90 BAD (HHHHHH)
Size 91: 43,91 BAD (HHHHHH)
Size 92: 43,92 BAD (HHHHHH)
Size 93: 44,93 BAD (HHHHHH)
Size 94: 44,94 BAD (HHHHHH)
Size 95: 45,95 BAD (HHHHHH)
Size 96: 45,96 BAD (HHHHHH)
Size 97: 46,97 BAD (HHHHHH)
Size 98: 46,98 BAD (HHHHHH)
Size 99: 46,99 BAD (HHHHHH)
Size 100: 47,100 BAD (HHHHHH)

View File

@@ -0,0 +1,633 @@
==================================
Code Page 437, Lucida Console font
==================================
Options: -face "Lucida Console" -family 0x36
Chars: A2 A3 2014 3044 30FC 4000
FontSurvey "-face \"Lucida Console\" -family 0x36"
Vista
-----
Size 1: 1,2 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 2,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 3,5 BAD (HHHHHH)
Size 6: 4,6 BAD (HHHHHH)
Size 7: 4,7 BAD (HHHHHH)
Size 8: 5,8 BAD (HHHHHH)
Size 9: 5,9 BAD (HHHHHH)
Size 10: 6,10 BAD (HHHHHH)
Size 11: 7,11 BAD (HHHHHH)
Size 12: 7,12 BAD (HHHHHH)
Size 13: 8,13 BAD (HHHHHH)
Size 14: 8,14 BAD (HHHHHH)
Size 15: 9,15 BAD (HHHHHH)
Size 16: 10,16 BAD (HHHHHH)
Size 17: 10,17 BAD (HHHHHH)
Size 18: 11,18 BAD (HHHHHH)
Size 19: 11,19 BAD (HHHHHH)
Size 20: 12,20 BAD (HHHHHH)
Size 21: 13,21 BAD (HHHHHH)
Size 22: 13,22 BAD (HHHHHH)
Size 23: 14,23 BAD (HHHHHH)
Size 24: 14,24 BAD (HHHHHH)
Size 25: 15,25 BAD (HHHHHH)
Size 26: 16,26 BAD (HHHHHH)
Size 27: 16,27 BAD (HHHHHH)
Size 28: 17,28 BAD (HHHHHH)
Size 29: 17,29 BAD (HHHHHH)
Size 30: 18,30 BAD (HHHHHH)
Size 31: 19,31 BAD (HHHHHH)
Size 32: 19,32 BAD (HHHHHH)
Size 33: 20,33 BAD (HHHHHH)
Size 34: 20,34 BAD (HHHHHH)
Size 35: 21,35 BAD (HHHHHH)
Size 36: 22,36 BAD (HHHHHH)
Size 37: 22,37 BAD (HHHHHH)
Size 38: 23,38 BAD (HHHHHH)
Size 39: 23,39 BAD (HHHHHH)
Size 40: 24,40 BAD (HHHHHH)
Size 41: 25,41 BAD (HHHHHH)
Size 42: 25,42 BAD (HHHHHH)
Size 43: 26,43 BAD (HHHHHH)
Size 44: 27,44 BAD (HHHHHH)
Size 45: 27,45 BAD (HHHHHH)
Size 46: 28,46 BAD (HHHHHH)
Size 47: 28,47 BAD (HHHHHH)
Size 48: 29,48 BAD (HHHHHH)
Size 49: 30,49 BAD (HHHHHH)
Size 50: 30,50 BAD (HHHHHH)
Size 51: 31,51 BAD (HHHHHH)
Size 52: 31,52 BAD (HHHHHH)
Size 53: 32,53 BAD (HHHHHH)
Size 54: 33,54 BAD (HHHHHH)
Size 55: 33,55 BAD (HHHHHH)
Size 56: 34,56 BAD (HHHHHH)
Size 57: 34,57 BAD (HHHHHH)
Size 58: 35,58 BAD (HHHHHH)
Size 59: 36,59 BAD (HHHHHH)
Size 60: 36,60 BAD (HHHHHH)
Size 61: 37,61 BAD (HHHHHH)
Size 62: 37,62 BAD (HHHHHH)
Size 63: 38,63 BAD (HHHHHH)
Size 64: 39,65 BAD (HHHHHH)
Size 65: 39,65 BAD (HHHHHH)
Size 66: 40,66 BAD (HHHHHH)
Size 67: 40,67 BAD (HHHHHH)
Size 68: 41,68 BAD (HHHHHH)
Size 69: 42,69 BAD (HHHHHH)
Size 70: 42,70 BAD (HHHHHH)
Size 71: 43,71 BAD (HHHHHH)
Size 72: 43,72 BAD (HHHHHH)
Size 73: 44,73 BAD (HHHHHH)
Size 74: 45,74 BAD (HHHHHH)
Size 75: 45,75 BAD (HHHHHH)
Size 76: 46,76 BAD (HHHHHH)
Size 77: 46,77 BAD (HHHHHH)
Size 78: 47,78 BAD (HHHHHH)
Size 79: 48,79 BAD (HHHHHH)
Size 80: 48,80 BAD (HHHHHH)
Size 81: 49,81 BAD (HHHHHH)
Size 82: 49,82 BAD (HHHHHH)
Size 83: 50,83 BAD (HHHHHH)
Size 84: 51,84 BAD (HHHHHH)
Size 85: 51,85 BAD (HHHHHH)
Size 86: 52,86 BAD (HHHHHH)
Size 87: 52,87 BAD (HHHHHH)
Size 88: 53,88 BAD (HHHHHH)
Size 89: 54,89 BAD (HHHHHH)
Size 90: 54,90 BAD (HHHHHH)
Size 91: 55,91 BAD (HHHHHH)
Size 92: 55,92 BAD (HHHHHH)
Size 93: 56,93 BAD (HHHHHH)
Size 94: 57,94 BAD (HHHHHH)
Size 95: 57,95 BAD (HHHHHH)
Size 96: 58,96 BAD (HHHHHH)
Size 97: 58,97 BAD (HHHHHH)
Size 98: 59,98 BAD (HHHHHH)
Size 99: 60,99 BAD (HHHHHH)
Size 100: 60,100 BAD (HHHHHH)
Windows 7
---------
Size 1: 1,2 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 2,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 3,5 BAD (HHHHHH)
Size 6: 4,6 BAD (HHHHHH)
Size 7: 4,7 BAD (HHHHHH)
Size 8: 5,8 BAD (HHHHHH)
Size 9: 5,9 BAD (HHHHHH)
Size 10: 6,10 BAD (HHHHHH)
Size 11: 7,11 BAD (HHHHHH)
Size 12: 7,12 BAD (HHHHHH)
Size 13: 8,13 BAD (HHHHHH)
Size 14: 8,14 BAD (HHHHHH)
Size 15: 9,15 BAD (HHHHHH)
Size 16: 10,16 BAD (HHHHHH)
Size 17: 10,17 BAD (HHHHHH)
Size 18: 11,18 BAD (HHHHHH)
Size 19: 11,19 BAD (HHHHHH)
Size 20: 12,20 BAD (HHHHHH)
Size 21: 13,21 BAD (HHHHHH)
Size 22: 13,22 BAD (HHHHHH)
Size 23: 14,23 BAD (HHHHHH)
Size 24: 14,24 BAD (HHHHHH)
Size 25: 15,25 BAD (HHHHHH)
Size 26: 16,26 BAD (HHHHHH)
Size 27: 16,27 BAD (HHHHHH)
Size 28: 17,28 BAD (HHHHHH)
Size 29: 17,29 BAD (HHHHHH)
Size 30: 18,30 BAD (HHHHHH)
Size 31: 19,31 BAD (HHHHHH)
Size 32: 19,32 BAD (HHHHHH)
Size 33: 20,33 BAD (HHHHHH)
Size 34: 20,34 BAD (HHHHHH)
Size 35: 21,35 BAD (HHHHHH)
Size 36: 22,36 BAD (HHHHHH)
Size 37: 22,37 BAD (HHHHHH)
Size 38: 23,38 BAD (HHHHHH)
Size 39: 23,39 BAD (HHHHHH)
Size 40: 24,40 BAD (HHHHHH)
Size 41: 25,41 BAD (HHHHHH)
Size 42: 25,42 BAD (HHHHHH)
Size 43: 26,43 BAD (HHHHHH)
Size 44: 27,44 BAD (HHHHHH)
Size 45: 27,45 BAD (HHHHHH)
Size 46: 28,46 BAD (HHHHHH)
Size 47: 28,47 BAD (HHHHHH)
Size 48: 29,48 BAD (HHHHHH)
Size 49: 30,49 BAD (HHHHHH)
Size 50: 30,50 BAD (HHHHHH)
Size 51: 31,51 BAD (HHHHHH)
Size 52: 31,52 BAD (HHHHHH)
Size 53: 32,53 BAD (HHHHHH)
Size 54: 33,54 BAD (HHHHHH)
Size 55: 33,55 BAD (HHHHHH)
Size 56: 34,56 BAD (HHHHHH)
Size 57: 34,57 BAD (HHHHHH)
Size 58: 35,58 BAD (HHHHHH)
Size 59: 36,59 BAD (HHHHHH)
Size 60: 36,60 BAD (HHHHHH)
Size 61: 37,61 BAD (HHHHHH)
Size 62: 37,62 BAD (HHHHHH)
Size 63: 38,63 BAD (HHHHHH)
Size 64: 39,65 BAD (HHHHHH)
Size 65: 39,65 BAD (HHHHHH)
Size 66: 40,66 BAD (HHHHHH)
Size 67: 40,67 BAD (HHHHHH)
Size 68: 41,68 BAD (HHHHHH)
Size 69: 42,69 BAD (HHHHHH)
Size 70: 42,70 BAD (HHHHHH)
Size 71: 43,71 BAD (HHHHHH)
Size 72: 43,72 BAD (HHHHHH)
Size 73: 44,73 BAD (HHHHHH)
Size 74: 45,74 BAD (HHHHHH)
Size 75: 45,75 BAD (HHHHHH)
Size 76: 46,76 BAD (HHHHHH)
Size 77: 46,77 BAD (HHHHHH)
Size 78: 47,78 BAD (HHHHHH)
Size 79: 48,79 BAD (HHHHHH)
Size 80: 48,80 BAD (HHHHHH)
Size 81: 49,81 BAD (HHHHHH)
Size 82: 49,82 BAD (HHHHHH)
Size 83: 50,83 BAD (HHHHHH)
Size 84: 51,84 BAD (HHHHHH)
Size 85: 51,85 BAD (HHHHHH)
Size 86: 52,86 BAD (HHHHHH)
Size 87: 52,87 BAD (HHHHHH)
Size 88: 53,88 BAD (HHHHHH)
Size 89: 54,89 BAD (HHHHHH)
Size 90: 54,90 BAD (HHHHHH)
Size 91: 55,91 BAD (HHHHHH)
Size 92: 55,92 BAD (HHHHHH)
Size 93: 56,93 BAD (HHHHHH)
Size 94: 57,94 BAD (HHHHHH)
Size 95: 57,95 BAD (HHHHHH)
Size 96: 58,96 BAD (HHHHHH)
Size 97: 58,97 BAD (HHHHHH)
Size 98: 59,98 BAD (HHHHHH)
Size 99: 60,99 BAD (HHHHHH)
Size 100: 60,100 BAD (HHHHHH)
Windows 8
---------
Size 1: 1,2 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 2,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 3,5 BAD (HHHHHH)
Size 6: 4,6 BAD (HHHHHH)
Size 7: 4,7 BAD (HHHHHH)
Size 8: 5,8 BAD (HHHHHH)
Size 9: 5,9 BAD (HHHHHH)
Size 10: 6,10 BAD (HHHHHH)
Size 11: 7,11 BAD (HHHHHH)
Size 12: 7,12 BAD (HHHHHH)
Size 13: 8,13 BAD (HHHHHH)
Size 14: 8,14 BAD (HHHHHH)
Size 15: 9,15 BAD (HHHHHH)
Size 16: 10,16 BAD (HHHHHH)
Size 17: 10,17 BAD (HHHHHH)
Size 18: 11,18 BAD (HHHHHH)
Size 19: 11,19 BAD (HHHHHH)
Size 20: 12,20 BAD (HHHHHH)
Size 21: 13,21 BAD (HHHHHH)
Size 22: 13,22 BAD (HHHHHH)
Size 23: 14,23 BAD (HHHHHH)
Size 24: 14,24 BAD (HHHHHH)
Size 25: 15,25 BAD (HHHHHH)
Size 26: 16,26 BAD (HHHHHH)
Size 27: 16,27 BAD (HHHHHH)
Size 28: 17,28 BAD (HHHHHH)
Size 29: 17,29 BAD (HHHHHH)
Size 30: 18,30 BAD (HHHHHH)
Size 31: 19,31 BAD (HHHHHH)
Size 32: 19,32 BAD (HHHHHH)
Size 33: 20,33 BAD (HHHHHH)
Size 34: 20,34 BAD (HHHHHH)
Size 35: 21,35 BAD (HHHHHH)
Size 36: 22,36 BAD (HHHHHH)
Size 37: 22,37 BAD (HHHHHH)
Size 38: 23,38 BAD (HHHHHH)
Size 39: 23,39 BAD (HHHHHH)
Size 40: 24,40 BAD (HHHHHH)
Size 41: 25,41 BAD (HHHHHH)
Size 42: 25,42 BAD (HHHHHH)
Size 43: 26,43 BAD (HHHHHH)
Size 44: 27,44 BAD (HHHHHH)
Size 45: 27,45 BAD (HHHHHH)
Size 46: 28,46 BAD (HHHHHH)
Size 47: 28,47 BAD (HHHHHH)
Size 48: 29,48 BAD (HHHHHH)
Size 49: 30,49 BAD (HHHHHH)
Size 50: 30,50 BAD (HHHHHH)
Size 51: 31,51 BAD (HHHHHH)
Size 52: 31,52 BAD (HHHHHH)
Size 53: 32,53 BAD (HHHHHH)
Size 54: 33,54 BAD (HHHHHH)
Size 55: 33,55 BAD (HHHHHH)
Size 56: 34,56 BAD (HHHHHH)
Size 57: 34,57 BAD (HHHHHH)
Size 58: 35,58 BAD (HHHHHH)
Size 59: 36,59 BAD (HHHHHH)
Size 60: 36,60 BAD (HHHHHH)
Size 61: 37,61 BAD (HHHHHH)
Size 62: 37,62 BAD (HHHHHH)
Size 63: 38,63 BAD (HHHHHH)
Size 64: 39,65 BAD (HHHHHH)
Size 65: 39,65 BAD (HHHHHH)
Size 66: 40,66 BAD (HHHHHH)
Size 67: 40,67 BAD (HHHHHH)
Size 68: 41,68 BAD (HHHHHH)
Size 69: 42,69 BAD (HHHHHH)
Size 70: 42,70 BAD (HHHHHH)
Size 71: 43,71 BAD (HHHHHH)
Size 72: 43,72 BAD (HHHHHH)
Size 73: 44,73 BAD (HHHHHH)
Size 74: 45,74 BAD (HHHHHH)
Size 75: 45,75 BAD (HHHHHH)
Size 76: 46,76 BAD (HHHHHH)
Size 77: 46,77 BAD (HHHHHH)
Size 78: 47,78 BAD (HHHHHH)
Size 79: 48,79 BAD (HHHHHH)
Size 80: 48,80 BAD (HHHHHH)
Size 81: 49,81 BAD (HHHHHH)
Size 82: 49,82 BAD (HHHHHH)
Size 83: 50,83 BAD (HHHHHH)
Size 84: 51,84 BAD (HHHHHH)
Size 85: 51,85 BAD (HHHHHH)
Size 86: 52,86 BAD (HHHHHH)
Size 87: 52,87 BAD (HHHHHH)
Size 88: 53,88 BAD (HHHHHH)
Size 89: 54,89 BAD (HHHHHH)
Size 90: 54,90 BAD (HHHHHH)
Size 91: 55,91 BAD (HHHHHH)
Size 92: 55,92 BAD (HHHHHH)
Size 93: 56,93 BAD (HHHHHH)
Size 94: 57,94 BAD (HHHHHH)
Size 95: 57,95 BAD (HHHHHH)
Size 96: 58,96 BAD (HHHHHH)
Size 97: 58,97 BAD (HHHHHH)
Size 98: 59,98 BAD (HHHHHH)
Size 99: 60,99 BAD (HHHHHH)
Size 100: 60,100 BAD (HHHHHH)
Windows 8.1
-----------
Size 1: 1,2 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 2,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 3,5 BAD (HHHHHH)
Size 6: 4,6 BAD (HHHHHH)
Size 7: 4,7 BAD (HHHHHH)
Size 8: 5,8 BAD (HHHHHH)
Size 9: 5,9 BAD (HHHHHH)
Size 10: 6,10 BAD (HHHHHH)
Size 11: 7,11 BAD (HHHHHH)
Size 12: 7,12 BAD (HHHHHH)
Size 13: 8,13 BAD (HHHHHH)
Size 14: 8,14 BAD (HHHHHH)
Size 15: 9,15 BAD (HHHHHH)
Size 16: 10,16 BAD (HHHHHH)
Size 17: 10,17 BAD (HHHHHH)
Size 18: 11,18 BAD (HHHHHH)
Size 19: 11,19 BAD (HHHHHH)
Size 20: 12,20 BAD (HHHHHH)
Size 21: 13,21 BAD (HHHHHH)
Size 22: 13,22 BAD (HHHHHH)
Size 23: 14,23 BAD (HHHHHH)
Size 24: 14,24 BAD (HHHHHH)
Size 25: 15,25 BAD (HHHHHH)
Size 26: 16,26 BAD (HHHHHH)
Size 27: 16,27 BAD (HHHHHH)
Size 28: 17,28 BAD (HHHHHH)
Size 29: 17,29 BAD (HHHHHH)
Size 30: 18,30 BAD (HHHHHH)
Size 31: 19,31 BAD (HHHHHH)
Size 32: 19,32 BAD (HHHHHH)
Size 33: 20,33 BAD (HHHHHH)
Size 34: 20,34 BAD (HHHHHH)
Size 35: 21,35 BAD (HHHHHH)
Size 36: 22,36 BAD (HHHHHH)
Size 37: 22,37 BAD (HHHHHH)
Size 38: 23,38 BAD (HHHHHH)
Size 39: 23,39 BAD (HHHHHH)
Size 40: 24,40 BAD (HHHHHH)
Size 41: 25,41 BAD (HHHHHH)
Size 42: 25,42 BAD (HHHHHH)
Size 43: 26,43 BAD (HHHHHH)
Size 44: 27,44 BAD (HHHHHH)
Size 45: 27,45 BAD (HHHHHH)
Size 46: 28,46 BAD (HHHHHH)
Size 47: 28,47 BAD (HHHHHH)
Size 48: 29,48 BAD (HHHHHH)
Size 49: 30,49 BAD (HHHHHH)
Size 50: 30,50 BAD (HHHHHH)
Size 51: 31,51 BAD (HHHHHH)
Size 52: 31,52 BAD (HHHHHH)
Size 53: 32,53 BAD (HHHHHH)
Size 54: 33,54 BAD (HHHHHH)
Size 55: 33,55 BAD (HHHHHH)
Size 56: 34,56 BAD (HHHHHH)
Size 57: 34,57 BAD (HHHHHH)
Size 58: 35,58 BAD (HHHHHH)
Size 59: 36,59 BAD (HHHHHH)
Size 60: 36,60 BAD (HHHHHH)
Size 61: 37,61 BAD (HHHHHH)
Size 62: 37,62 BAD (HHHHHH)
Size 63: 38,63 BAD (HHHHHH)
Size 64: 39,65 BAD (HHHHHH)
Size 65: 39,65 BAD (HHHHHH)
Size 66: 40,66 BAD (HHHHHH)
Size 67: 40,67 BAD (HHHHHH)
Size 68: 41,68 BAD (HHHHHH)
Size 69: 42,69 BAD (HHHHHH)
Size 70: 42,70 BAD (HHHHHH)
Size 71: 43,71 BAD (HHHHHH)
Size 72: 43,72 BAD (HHHHHH)
Size 73: 44,73 BAD (HHHHHH)
Size 74: 45,74 BAD (HHHHHH)
Size 75: 45,75 BAD (HHHHHH)
Size 76: 46,76 BAD (HHHHHH)
Size 77: 46,77 BAD (HHHHHH)
Size 78: 47,78 BAD (HHHHHH)
Size 79: 48,79 BAD (HHHHHH)
Size 80: 48,80 BAD (HHHHHH)
Size 81: 49,81 BAD (HHHHHH)
Size 82: 49,82 BAD (HHHHHH)
Size 83: 50,83 BAD (HHHHHH)
Size 84: 51,84 BAD (HHHHHH)
Size 85: 51,85 BAD (HHHHHH)
Size 86: 52,86 BAD (HHHHHH)
Size 87: 52,87 BAD (HHHHHH)
Size 88: 53,88 BAD (HHHHHH)
Size 89: 54,89 BAD (HHHHHH)
Size 90: 54,90 BAD (HHHHHH)
Size 91: 55,91 BAD (HHHHHH)
Size 92: 55,92 BAD (HHHHHH)
Size 93: 56,93 BAD (HHHHHH)
Size 94: 57,94 BAD (HHHHHH)
Size 95: 57,95 BAD (HHHHHH)
Size 96: 58,96 BAD (HHHHHH)
Size 97: 58,97 BAD (HHHHHH)
Size 98: 59,98 BAD (HHHHHH)
Size 99: 60,99 BAD (HHHHHH)
Size 100: 60,100 BAD (HHHHHH)
Windows 10 14342 Old Console
----------------------------
Size 1: 1,2 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 2,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 3,5 BAD (HHHHHH)
Size 6: 4,6 BAD (HHHHHH)
Size 7: 4,7 BAD (HHHHHH)
Size 8: 5,8 BAD (HHHHHH)
Size 9: 5,9 BAD (HHHHHH)
Size 10: 6,10 BAD (HHHHHH)
Size 11: 7,11 BAD (HHHHHH)
Size 12: 7,12 BAD (HHHHHH)
Size 13: 8,13 BAD (HHHHHH)
Size 14: 8,14 BAD (HHHHHH)
Size 15: 9,15 BAD (HHHHHH)
Size 16: 10,16 BAD (HHHHHH)
Size 17: 10,17 BAD (HHHHHH)
Size 18: 11,18 BAD (HHHHHH)
Size 19: 11,19 BAD (HHHHHH)
Size 20: 12,20 BAD (HHHHHH)
Size 21: 13,21 BAD (HHHHHH)
Size 22: 13,22 BAD (HHHHHH)
Size 23: 14,23 BAD (HHHHHH)
Size 24: 14,24 BAD (HHHHHH)
Size 25: 15,25 BAD (HHHHHH)
Size 26: 16,26 BAD (HHHHHH)
Size 27: 16,27 BAD (HHHHHH)
Size 28: 17,28 BAD (HHHHHH)
Size 29: 17,29 BAD (HHHHHH)
Size 30: 18,30 BAD (HHHHHH)
Size 31: 19,31 BAD (HHHHHH)
Size 32: 19,32 BAD (HHHHHH)
Size 33: 20,33 BAD (HHHHHH)
Size 34: 20,34 BAD (HHHHHH)
Size 35: 21,35 BAD (HHHHHH)
Size 36: 22,36 BAD (HHHHHH)
Size 37: 22,37 BAD (HHHHHH)
Size 38: 23,38 BAD (HHHHHH)
Size 39: 23,39 BAD (HHHHHH)
Size 40: 24,40 BAD (HHHHHH)
Size 41: 25,41 BAD (HHHHHH)
Size 42: 25,42 BAD (HHHHHH)
Size 43: 26,43 BAD (HHHHHH)
Size 44: 27,44 BAD (HHHHHH)
Size 45: 27,45 BAD (HHHHHH)
Size 46: 28,46 BAD (HHHHHH)
Size 47: 28,47 BAD (HHHHHH)
Size 48: 29,48 BAD (HHHHHH)
Size 49: 30,49 BAD (HHHHHH)
Size 50: 30,50 BAD (HHHHHH)
Size 51: 31,51 BAD (HHHHHH)
Size 52: 31,52 BAD (HHHHHH)
Size 53: 32,53 BAD (HHHHHH)
Size 54: 33,54 BAD (HHHHHH)
Size 55: 33,55 BAD (HHHHHH)
Size 56: 34,56 BAD (HHHHHH)
Size 57: 34,57 BAD (HHHHHH)
Size 58: 35,58 BAD (HHHHHH)
Size 59: 36,59 BAD (HHHHHH)
Size 60: 36,60 BAD (HHHHHH)
Size 61: 37,61 BAD (HHHHHH)
Size 62: 37,62 BAD (HHHHHH)
Size 63: 38,63 BAD (HHHHHH)
Size 64: 39,65 BAD (HHHHHH)
Size 65: 39,65 BAD (HHHHHH)
Size 66: 40,66 BAD (HHHHHH)
Size 67: 40,67 BAD (HHHHHH)
Size 68: 41,68 BAD (HHHHHH)
Size 69: 42,69 BAD (HHHHHH)
Size 70: 42,70 BAD (HHHHHH)
Size 71: 43,71 BAD (HHHHHH)
Size 72: 43,72 BAD (HHHHHH)
Size 73: 44,73 BAD (HHHHHH)
Size 74: 45,74 BAD (HHHHHH)
Size 75: 45,75 BAD (HHHHHH)
Size 76: 46,76 BAD (HHHHHH)
Size 77: 46,77 BAD (HHHHHH)
Size 78: 47,78 BAD (HHHHHH)
Size 79: 48,79 BAD (HHHHHH)
Size 80: 48,80 BAD (HHHHHH)
Size 81: 49,81 BAD (HHHHHH)
Size 82: 49,82 BAD (HHHHHH)
Size 83: 50,83 BAD (HHHHHH)
Size 84: 51,84 BAD (HHHHHH)
Size 85: 51,85 BAD (HHHHHH)
Size 86: 52,86 BAD (HHHHHH)
Size 87: 52,87 BAD (HHHHHH)
Size 88: 53,88 BAD (HHHHHH)
Size 89: 54,89 BAD (HHHHHH)
Size 90: 54,90 BAD (HHHHHH)
Size 91: 55,91 BAD (HHHHHH)
Size 92: 55,92 BAD (HHHHHH)
Size 93: 56,93 BAD (HHHHHH)
Size 94: 57,94 BAD (HHHHHH)
Size 95: 57,95 BAD (HHHHHH)
Size 96: 58,96 BAD (HHHHHH)
Size 97: 58,97 BAD (HHHHHH)
Size 98: 59,98 BAD (HHHHHH)
Size 99: 60,99 BAD (HHHHHH)
Size 100: 60,100 BAD (HHHHHH)
Windows 10 14342 New Console
----------------------------
Size 1: 1,1 BAD (HHHHHH)
Size 2: 1,2 BAD (HHHHHH)
Size 3: 2,3 BAD (HHHHHH)
Size 4: 2,4 BAD (HHHHHH)
Size 5: 3,5 BAD (HHHHHH)
Size 6: 4,6 BAD (HHHHHH)
Size 7: 4,7 BAD (HHHHHH)
Size 8: 5,8 BAD (HHHHHH)
Size 9: 5,9 BAD (HHHHHH)
Size 10: 6,10 BAD (HHHHHH)
Size 11: 7,11 BAD (HHHHHH)
Size 12: 7,12 BAD (HHHHHH)
Size 13: 8,13 BAD (HHHHHH)
Size 14: 8,14 BAD (HHHHHH)
Size 15: 9,15 BAD (HHHHHH)
Size 16: 10,16 BAD (HHHHHH)
Size 17: 10,17 BAD (HHHHHH)
Size 18: 11,18 BAD (HHHHHH)
Size 19: 11,19 BAD (HHHHHH)
Size 20: 12,20 BAD (HHHHHH)
Size 21: 13,21 BAD (HHHHHH)
Size 22: 13,22 BAD (HHHHHH)
Size 23: 14,23 BAD (HHHHHH)
Size 24: 14,24 BAD (HHHHHH)
Size 25: 15,25 BAD (HHHHHH)
Size 26: 16,26 BAD (HHHHHH)
Size 27: 16,27 BAD (HHHHHH)
Size 28: 17,28 BAD (HHHHHH)
Size 29: 17,29 BAD (HHHHHH)
Size 30: 18,30 BAD (HHHHHH)
Size 31: 19,31 BAD (HHHHHH)
Size 32: 19,32 BAD (HHHHHH)
Size 33: 20,33 BAD (HHHHHH)
Size 34: 20,34 BAD (HHHHHH)
Size 35: 21,35 BAD (HHHHHH)
Size 36: 22,36 BAD (HHHHHH)
Size 37: 22,37 BAD (HHHHHH)
Size 38: 23,38 BAD (HHHHHH)
Size 39: 23,39 BAD (HHHHHH)
Size 40: 24,40 BAD (HHHHHH)
Size 41: 25,41 BAD (HHHHHH)
Size 42: 25,42 BAD (HHHHHH)
Size 43: 26,43 BAD (HHHHHH)
Size 44: 27,44 BAD (HHHHHH)
Size 45: 27,45 BAD (HHHHHH)
Size 46: 28,46 BAD (HHHHHH)
Size 47: 28,47 BAD (HHHHHH)
Size 48: 29,48 BAD (HHHHHH)
Size 49: 30,49 BAD (HHHHHH)
Size 50: 30,50 BAD (HHHHHH)
Size 51: 31,51 BAD (HHHHHH)
Size 52: 31,52 BAD (HHHHHH)
Size 53: 32,53 BAD (HHHHHH)
Size 54: 33,54 BAD (HHHHHH)
Size 55: 33,55 BAD (HHHHHH)
Size 56: 34,56 BAD (HHHHHH)
Size 57: 34,57 BAD (HHHHHH)
Size 58: 35,58 BAD (HHHHHH)
Size 59: 36,59 BAD (HHHHHH)
Size 60: 36,60 BAD (HHHHHH)
Size 61: 37,61 BAD (HHHHHH)
Size 62: 37,62 BAD (HHHHHH)
Size 63: 38,63 BAD (HHHHHH)
Size 64: 39,64 BAD (HHHHHH)
Size 65: 39,65 BAD (HHHHHH)
Size 66: 40,66 BAD (HHHHHH)
Size 67: 40,67 BAD (HHHHHH)
Size 68: 41,68 BAD (HHHHHH)
Size 69: 42,69 BAD (HHHHHH)
Size 70: 42,70 BAD (HHHHHH)
Size 71: 43,71 BAD (HHHHHH)
Size 72: 43,72 BAD (HHHHHH)
Size 73: 44,73 BAD (HHHHHH)
Size 74: 45,74 BAD (HHHHHH)
Size 75: 45,75 BAD (HHHHHH)
Size 76: 46,76 BAD (HHHHHH)
Size 77: 46,77 BAD (HHHHHH)
Size 78: 47,78 BAD (HHHHHH)
Size 79: 48,79 BAD (HHHHHH)
Size 80: 48,80 BAD (HHHHHH)
Size 81: 49,81 BAD (HHHHHH)
Size 82: 49,82 BAD (HHHHHH)
Size 83: 50,83 BAD (HHHHHH)
Size 84: 51,84 BAD (HHHHHH)
Size 85: 51,85 BAD (HHHHHH)
Size 86: 52,86 BAD (HHHHHH)
Size 87: 52,87 BAD (HHHHHH)
Size 88: 53,88 BAD (HHHHHH)
Size 89: 54,89 BAD (HHHHHH)
Size 90: 54,90 BAD (HHHHHH)
Size 91: 55,91 BAD (HHHHHH)
Size 92: 55,92 BAD (HHHHHH)
Size 93: 56,93 BAD (HHHHHH)
Size 94: 57,94 BAD (HHHHHH)
Size 95: 57,95 BAD (HHHHHH)
Size 96: 58,96 BAD (HHHHHH)
Size 97: 58,97 BAD (HHHHHH)
Size 98: 59,98 BAD (HHHHHH)
Size 99: 60,99 BAD (HHHHHH)
Size 100: 60,100 BAD (HHHHHH)

View File

@@ -0,0 +1,630 @@
=======================================
Code Page 932, Japanese, MS Gothic font
=======================================
Options: -face-gothic -family 0x36
Chars: A2 A3 2014 3044 30FC 4000
Vista
-----
Size 1: 1,2 OK (HHHFFF)
Size 2: 1,2 OK (HHHFFF)
Size 3: 2,3 BAD (FFFFHH)
Size 4: 2,4 OK (HHHFFF)
Size 5: 3,5 OK (HHHFFF)
Size 6: 3,6 OK (HHHFFF)
Size 7: 4,7 OK (HHHFFF)
Size 8: 4,8 OK (HHHFFF)
Size 9: 5,9 OK (HHHFFF)
Size 10: 5,10 OK (HHHFFF)
Size 11: 6,11 OK (HHHFFF)
Size 12: 6,12 OK (HHHFFF)
Size 13: 7,13 OK (HHHFFF)
Size 14: 7,14 BAD (HHHFHH)
Size 15: 8,15 OK (HHHFFF)
Size 16: 8,16 BAD (HHHFHH)
Size 17: 9,17 OK (HHHFFF)
Size 18: 9,18 BAD (HHHFHH)
Size 19: 10,19 OK (HHHFFF)
Size 20: 10,20 BAD (HHHFHH)
Size 21: 11,21 OK (HHHFFF)
Size 22: 11,22 BAD (HHHFHH)
Size 23: 12,23 BAD (HHHFHH)
Size 24: 12,24 BAD (HHHFHH)
Size 25: 13,25 BAD (HHHFHH)
Size 26: 13,26 BAD (HHHFHH)
Size 27: 14,27 BAD (HHHFHH)
Size 28: 14,28 BAD (HHHFHH)
Size 29: 15,29 BAD (HHHFHH)
Size 30: 15,30 BAD (HHHFHH)
Size 31: 16,31 BAD (HHHFHH)
Size 32: 16,33 BAD (HHHFHH)
Size 33: 17,33 BAD (HHHFHH)
Size 34: 17,34 BAD (HHHFHH)
Size 35: 18,35 BAD (HHHFHH)
Size 36: 18,36 BAD (HHHFHH)
Size 37: 19,37 BAD (HHHFHH)
Size 38: 19,38 BAD (HHHFHH)
Size 39: 20,39 BAD (HHHFHH)
Size 40: 20,40 BAD (HHHFHH)
Size 41: 21,41 BAD (HHHFHH)
Size 42: 21,42 BAD (HHHFHH)
Size 43: 22,43 BAD (HHHFHH)
Size 44: 22,44 BAD (HHHFHH)
Size 45: 23,45 BAD (HHHFHH)
Size 46: 23,46 BAD (HHHFHH)
Size 47: 24,47 BAD (HHHFHH)
Size 48: 24,48 BAD (HHHFHH)
Size 49: 25,49 BAD (HHHFHH)
Size 50: 25,50 BAD (HHHFHH)
Size 51: 26,51 BAD (HHHFHH)
Size 52: 26,52 BAD (HHHFHH)
Size 53: 27,53 BAD (HHHFHH)
Size 54: 27,54 BAD (HHHFHH)
Size 55: 28,55 BAD (HHHFHH)
Size 56: 28,56 BAD (HHHFHH)
Size 57: 29,57 BAD (HHHFHH)
Size 58: 29,58 BAD (HHHFHH)
Size 59: 30,59 BAD (HHHFHH)
Size 60: 30,60 BAD (HHHFHH)
Size 61: 31,61 BAD (HHHFHH)
Size 62: 31,62 BAD (HHHFHH)
Size 63: 32,63 BAD (HHHFHH)
Size 64: 32,64 BAD (HHHFHH)
Size 65: 33,65 BAD (HHHFHH)
Size 66: 33,66 BAD (HHHFHH)
Size 67: 34,67 BAD (HHHFHH)
Size 68: 34,68 BAD (HHHFHH)
Size 69: 35,69 BAD (HHHFHH)
Size 70: 35,70 BAD (HHHFHH)
Size 71: 36,71 BAD (HHHFHH)
Size 72: 36,72 BAD (HHHFHH)
Size 73: 37,73 BAD (HHHFHH)
Size 74: 37,74 BAD (HHHFHH)
Size 75: 38,75 BAD (HHHFHH)
Size 76: 38,76 BAD (HHHFHH)
Size 77: 39,77 BAD (HHHFHH)
Size 78: 39,78 BAD (HHHFHH)
Size 79: 40,79 BAD (HHHFHH)
Size 80: 40,80 BAD (HHHFHH)
Size 81: 41,81 BAD (HHHFHH)
Size 82: 41,82 BAD (HHHFHH)
Size 83: 42,83 BAD (HHHFHH)
Size 84: 42,84 BAD (HHHFHH)
Size 85: 43,85 BAD (HHHFHH)
Size 86: 43,86 BAD (HHHFHH)
Size 87: 44,87 BAD (HHHFHH)
Size 88: 44,88 BAD (HHHFHH)
Size 89: 45,89 BAD (HHHFHH)
Size 90: 45,90 BAD (HHHFHH)
Size 91: 46,91 BAD (HHHFHH)
Size 92: 46,92 BAD (HHHFHH)
Size 93: 47,93 BAD (HHHFHH)
Size 94: 47,94 BAD (HHHFHH)
Size 95: 48,95 BAD (HHHFHH)
Size 96: 48,97 BAD (HHHFHH)
Size 97: 49,97 BAD (HHHFHH)
Size 98: 49,98 BAD (HHHFHH)
Size 99: 50,99 BAD (HHHFHH)
Size 100: 50,100 BAD (HHHFHH)
Windows 7
---------
Size 1: 1,2 OK (HHHFFF)
Size 2: 1,2 OK (HHHFFF)
Size 3: 2,3 BAD (FFFFHH)
Size 4: 2,4 OK (HHHFFF)
Size 5: 3,5 OK (HHHFFF)
Size 6: 3,6 OK (HHHFFF)
Size 7: 4,7 OK (HHHFFF)
Size 8: 4,8 OK (HHHFFF)
Size 9: 5,9 OK (HHHFFF)
Size 10: 5,10 OK (HHHFFF)
Size 11: 6,11 OK (HHHFFF)
Size 12: 6,12 OK (HHHFFF)
Size 13: 7,13 OK (HHHFFF)
Size 14: 7,14 BAD (FFFFFF)
Size 15: 8,15 OK (HHHFFF)
Size 16: 8,16 BAD (FFFFFF)
Size 17: 9,17 OK (HHHFFF)
Size 18: 9,18 BAD (FFFFFF)
Size 19: 10,19 OK (HHHFFF)
Size 20: 10,20 BAD (FFFFFF)
Size 21: 11,21 OK (HHHFFF)
Size 22: 11,22 BAD (FFFFFF)
Size 23: 12,23 BAD (FFFFFF)
Size 24: 12,24 BAD (FFFFFF)
Size 25: 13,25 BAD (FFFFFF)
Size 26: 13,26 BAD (FFFFFF)
Size 27: 14,27 BAD (FFFFFF)
Size 28: 14,28 BAD (FFFFFF)
Size 29: 15,29 BAD (FFFFFF)
Size 30: 15,30 BAD (FFFFFF)
Size 31: 16,31 BAD (FFFFFF)
Size 32: 16,33 BAD (FFFFFF)
Size 33: 17,33 BAD (FFFFFF)
Size 34: 17,34 BAD (FFFFFF)
Size 35: 18,35 BAD (FFFFFF)
Size 36: 18,36 BAD (FFFFFF)
Size 37: 19,37 BAD (FFFFFF)
Size 38: 19,38 BAD (FFFFFF)
Size 39: 20,39 BAD (FFFFFF)
Size 40: 20,40 BAD (FFFFFF)
Size 41: 21,41 BAD (FFFFFF)
Size 42: 21,42 BAD (FFFFFF)
Size 43: 22,43 BAD (FFFFFF)
Size 44: 22,44 BAD (FFFFFF)
Size 45: 23,45 BAD (FFFFFF)
Size 46: 23,46 BAD (FFFFFF)
Size 47: 24,47 BAD (FFFFFF)
Size 48: 24,48 BAD (FFFFFF)
Size 49: 25,49 BAD (FFFFFF)
Size 50: 25,50 BAD (FFFFFF)
Size 51: 26,51 BAD (FFFFFF)
Size 52: 26,52 BAD (FFFFFF)
Size 53: 27,53 BAD (FFFFFF)
Size 54: 27,54 BAD (FFFFFF)
Size 55: 28,55 BAD (FFFFFF)
Size 56: 28,56 BAD (FFFFFF)
Size 57: 29,57 BAD (FFFFFF)
Size 58: 29,58 BAD (FFFFFF)
Size 59: 30,59 BAD (FFFFFF)
Size 60: 30,60 BAD (FFFFFF)
Size 61: 31,61 BAD (FFFFFF)
Size 62: 31,62 BAD (FFFFFF)
Size 63: 32,63 BAD (FFFFFF)
Size 64: 32,64 BAD (FFFFFF)
Size 65: 33,65 BAD (FFFFFF)
Size 66: 33,66 BAD (FFFFFF)
Size 67: 34,67 BAD (FFFFFF)
Size 68: 34,68 BAD (FFFFFF)
Size 69: 35,69 BAD (FFFFFF)
Size 70: 35,70 BAD (FFFFFF)
Size 71: 36,71 BAD (FFFFFF)
Size 72: 36,72 BAD (FFFFFF)
Size 73: 37,73 BAD (FFFFFF)
Size 74: 37,74 BAD (FFFFFF)
Size 75: 38,75 BAD (FFFFFF)
Size 76: 38,76 BAD (FFFFFF)
Size 77: 39,77 BAD (FFFFFF)
Size 78: 39,78 BAD (FFFFFF)
Size 79: 40,79 BAD (FFFFFF)
Size 80: 40,80 BAD (FFFFFF)
Size 81: 41,81 BAD (FFFFFF)
Size 82: 41,82 BAD (FFFFFF)
Size 83: 42,83 BAD (FFFFFF)
Size 84: 42,84 BAD (FFFFFF)
Size 85: 43,85 BAD (FFFFFF)
Size 86: 43,86 BAD (FFFFFF)
Size 87: 44,87 BAD (FFFFFF)
Size 88: 44,88 BAD (FFFFFF)
Size 89: 45,89 BAD (FFFFFF)
Size 90: 45,90 BAD (FFFFFF)
Size 91: 46,91 BAD (FFFFFF)
Size 92: 46,92 BAD (FFFFFF)
Size 93: 47,93 BAD (FFFFFF)
Size 94: 47,94 BAD (FFFFFF)
Size 95: 48,95 BAD (FFFFFF)
Size 96: 48,97 BAD (FFFFFF)
Size 97: 49,97 BAD (FFFFFF)
Size 98: 49,98 BAD (FFFFFF)
Size 99: 50,99 BAD (FFFFFF)
Size 100: 50,100 BAD (FFFFFF)
Windows 8
---------
Size 1: 1,2 BAD (FFFFHH)
Size 2: 1,2 BAD (FFFFHH)
Size 3: 2,3 BAD (FFFFFF)
Size 4: 2,4 BAD (FFFFHH)
Size 5: 3,5 BAD (FFFFFF)
Size 6: 3,6 BAD (FFFFHH)
Size 7: 4,7 BAD (FFFFFF)
Size 8: 4,8 BAD (FFFFHH)
Size 9: 5,9 BAD (FFFFFF)
Size 10: 5,10 BAD (FFFFHH)
Size 11: 6,11 BAD (FFFFFF)
Size 12: 6,12 BAD (FFFFHH)
Size 13: 7,13 BAD (FFFFFF)
Size 14: 7,14 BAD (FFFFHH)
Size 15: 8,15 BAD (FFFFFF)
Size 16: 8,16 BAD (FFFFHH)
Size 17: 9,17 BAD (FFFFFF)
Size 18: 9,18 BAD (FFFFHH)
Size 19: 10,19 BAD (FFFFFF)
Size 20: 10,20 BAD (FFFFFF)
Size 21: 11,21 BAD (FFFFFF)
Size 22: 11,22 BAD (FFFFFF)
Size 23: 12,23 BAD (FFFFFF)
Size 24: 12,24 BAD (FFFFFF)
Size 25: 13,25 BAD (FFFFFF)
Size 26: 13,26 BAD (FFFFFF)
Size 27: 14,27 BAD (FFFFFF)
Size 28: 14,28 BAD (FFFFFF)
Size 29: 15,29 BAD (FFFFFF)
Size 30: 15,30 BAD (FFFFFF)
Size 31: 16,31 BAD (FFFFFF)
Size 32: 16,33 BAD (FFFFFF)
Size 33: 17,33 BAD (FFFFFF)
Size 34: 17,34 BAD (FFFFFF)
Size 35: 18,35 BAD (FFFFFF)
Size 36: 18,36 BAD (FFFFFF)
Size 37: 19,37 BAD (FFFFFF)
Size 38: 19,38 BAD (FFFFFF)
Size 39: 20,39 BAD (FFFFFF)
Size 40: 20,40 BAD (FFFFFF)
Size 41: 21,41 BAD (FFFFFF)
Size 42: 21,42 BAD (FFFFFF)
Size 43: 22,43 BAD (FFFFFF)
Size 44: 22,44 BAD (FFFFFF)
Size 45: 23,45 BAD (FFFFFF)
Size 46: 23,46 BAD (FFFFFF)
Size 47: 24,47 BAD (FFFFFF)
Size 48: 24,48 BAD (FFFFFF)
Size 49: 25,49 BAD (FFFFFF)
Size 50: 25,50 BAD (FFFFFF)
Size 51: 26,51 BAD (FFFFFF)
Size 52: 26,52 BAD (FFFFFF)
Size 53: 27,53 BAD (FFFFFF)
Size 54: 27,54 BAD (FFFFFF)
Size 55: 28,55 BAD (FFFFFF)
Size 56: 28,56 BAD (FFFFFF)
Size 57: 29,57 BAD (FFFFFF)
Size 58: 29,58 BAD (FFFFFF)
Size 59: 30,59 BAD (FFFFFF)
Size 60: 30,60 BAD (FFFFFF)
Size 61: 31,61 BAD (FFFFFF)
Size 62: 31,62 BAD (FFFFFF)
Size 63: 32,63 BAD (FFFFFF)
Size 64: 32,64 BAD (FFFFFF)
Size 65: 33,65 BAD (FFFFFF)
Size 66: 33,66 BAD (FFFFFF)
Size 67: 34,67 BAD (FFFFFF)
Size 68: 34,68 BAD (FFFFFF)
Size 69: 35,69 BAD (FFFFFF)
Size 70: 35,70 BAD (FFFFFF)
Size 71: 36,71 BAD (FFFFFF)
Size 72: 36,72 BAD (FFFFFF)
Size 73: 37,73 BAD (FFFFFF)
Size 74: 37,74 BAD (FFFFFF)
Size 75: 38,75 BAD (FFFFFF)
Size 76: 38,76 BAD (FFFFFF)
Size 77: 39,77 BAD (FFFFFF)
Size 78: 39,78 BAD (FFFFFF)
Size 79: 40,79 BAD (FFFFFF)
Size 80: 40,80 BAD (FFFFFF)
Size 81: 41,81 BAD (FFFFFF)
Size 82: 41,82 BAD (FFFFFF)
Size 83: 42,83 BAD (FFFFFF)
Size 84: 42,84 BAD (FFFFFF)
Size 85: 43,85 BAD (FFFFFF)
Size 86: 43,86 BAD (FFFFFF)
Size 87: 44,87 BAD (FFFFFF)
Size 88: 44,88 BAD (FFFFFF)
Size 89: 45,89 BAD (FFFFFF)
Size 90: 45,90 BAD (FFFFFF)
Size 91: 46,91 BAD (FFFFFF)
Size 92: 46,92 BAD (FFFFFF)
Size 93: 47,93 BAD (FFFFFF)
Size 94: 47,94 BAD (FFFFFF)
Size 95: 48,95 BAD (FFFFFF)
Size 96: 48,97 BAD (FFFFFF)
Size 97: 49,97 BAD (FFFFFF)
Size 98: 49,98 BAD (FFFFFF)
Size 99: 50,99 BAD (FFFFFF)
Size 100: 50,100 BAD (FFFFFF)
Windows 8.1
-----------
Size 1: 1,2 BAD (FFFFHH)
Size 2: 1,2 BAD (FFFFHH)
Size 3: 2,3 BAD (FFFFFF)
Size 4: 2,4 BAD (FFFFHH)
Size 5: 3,5 BAD (FFFFFF)
Size 6: 3,6 BAD (FFFFHH)
Size 7: 4,7 BAD (FFFFFF)
Size 8: 4,8 BAD (FFFFHH)
Size 9: 5,9 BAD (FFFFFF)
Size 10: 5,10 BAD (FFFFHH)
Size 11: 6,11 BAD (FFFFFF)
Size 12: 6,12 BAD (FFFFHH)
Size 13: 7,13 BAD (FFFFFF)
Size 14: 7,14 BAD (FFFFHH)
Size 15: 8,15 BAD (FFFFFF)
Size 16: 8,16 BAD (FFFFHH)
Size 17: 9,17 BAD (FFFFFF)
Size 18: 9,18 BAD (FFFFHH)
Size 19: 10,19 BAD (FFFFFF)
Size 20: 10,20 BAD (FFFFFF)
Size 21: 11,21 BAD (FFFFFF)
Size 22: 11,22 BAD (FFFFFF)
Size 23: 12,23 BAD (FFFFFF)
Size 24: 12,24 BAD (FFFFFF)
Size 25: 13,25 BAD (FFFFFF)
Size 26: 13,26 BAD (FFFFFF)
Size 27: 14,27 BAD (FFFFFF)
Size 28: 14,28 BAD (FFFFFF)
Size 29: 15,29 BAD (FFFFFF)
Size 30: 15,30 BAD (FFFFFF)
Size 31: 16,31 BAD (FFFFFF)
Size 32: 16,33 BAD (FFFFFF)
Size 33: 17,33 BAD (FFFFFF)
Size 34: 17,34 BAD (FFFFFF)
Size 35: 18,35 BAD (FFFFFF)
Size 36: 18,36 BAD (FFFFFF)
Size 37: 19,37 BAD (FFFFFF)
Size 38: 19,38 BAD (FFFFFF)
Size 39: 20,39 BAD (FFFFFF)
Size 40: 20,40 BAD (FFFFFF)
Size 41: 21,41 BAD (FFFFFF)
Size 42: 21,42 BAD (FFFFFF)
Size 43: 22,43 BAD (FFFFFF)
Size 44: 22,44 BAD (FFFFFF)
Size 45: 23,45 BAD (FFFFFF)
Size 46: 23,46 BAD (FFFFFF)
Size 47: 24,47 BAD (FFFFFF)
Size 48: 24,48 BAD (FFFFFF)
Size 49: 25,49 BAD (FFFFFF)
Size 50: 25,50 BAD (FFFFFF)
Size 51: 26,51 BAD (FFFFFF)
Size 52: 26,52 BAD (FFFFFF)
Size 53: 27,53 BAD (FFFFFF)
Size 54: 27,54 BAD (FFFFFF)
Size 55: 28,55 BAD (FFFFFF)
Size 56: 28,56 BAD (FFFFFF)
Size 57: 29,57 BAD (FFFFFF)
Size 58: 29,58 BAD (FFFFFF)
Size 59: 30,59 BAD (FFFFFF)
Size 60: 30,60 BAD (FFFFFF)
Size 61: 31,61 BAD (FFFFFF)
Size 62: 31,62 BAD (FFFFFF)
Size 63: 32,63 BAD (FFFFFF)
Size 64: 32,64 BAD (FFFFFF)
Size 65: 33,65 BAD (FFFFFF)
Size 66: 33,66 BAD (FFFFFF)
Size 67: 34,67 BAD (FFFFFF)
Size 68: 34,68 BAD (FFFFFF)
Size 69: 35,69 BAD (FFFFFF)
Size 70: 35,70 BAD (FFFFFF)
Size 71: 36,71 BAD (FFFFFF)
Size 72: 36,72 BAD (FFFFFF)
Size 73: 37,73 BAD (FFFFFF)
Size 74: 37,74 BAD (FFFFFF)
Size 75: 38,75 BAD (FFFFFF)
Size 76: 38,76 BAD (FFFFFF)
Size 77: 39,77 BAD (FFFFFF)
Size 78: 39,78 BAD (FFFFFF)
Size 79: 40,79 BAD (FFFFFF)
Size 80: 40,80 BAD (FFFFFF)
Size 81: 41,81 BAD (FFFFFF)
Size 82: 41,82 BAD (FFFFFF)
Size 83: 42,83 BAD (FFFFFF)
Size 84: 42,84 BAD (FFFFFF)
Size 85: 43,85 BAD (FFFFFF)
Size 86: 43,86 BAD (FFFFFF)
Size 87: 44,87 BAD (FFFFFF)
Size 88: 44,88 BAD (FFFFFF)
Size 89: 45,89 BAD (FFFFFF)
Size 90: 45,90 BAD (FFFFFF)
Size 91: 46,91 BAD (FFFFFF)
Size 92: 46,92 BAD (FFFFFF)
Size 93: 47,93 BAD (FFFFFF)
Size 94: 47,94 BAD (FFFFFF)
Size 95: 48,95 BAD (FFFFFF)
Size 96: 48,97 BAD (FFFFFF)
Size 97: 49,97 BAD (FFFFFF)
Size 98: 49,98 BAD (FFFFFF)
Size 99: 50,99 BAD (FFFFFF)
Size 100: 50,100 BAD (FFFFFF)
Windows 10 14342 Old Console
----------------------------
Size 1: 1,2 BAD (FFFFHH)
Size 2: 1,2 BAD (FFFFHH)
Size 3: 2,3 BAD (FFFFFF)
Size 4: 2,4 BAD (FFFFHH)
Size 5: 3,5 BAD (FFFFFF)
Size 6: 3,6 BAD (FFFFHH)
Size 7: 4,7 BAD (FFFFFF)
Size 8: 4,8 BAD (FFFFHH)
Size 9: 5,9 BAD (FFFFFF)
Size 10: 5,10 BAD (FFFFHH)
Size 11: 6,11 BAD (FFFFFF)
Size 12: 6,12 BAD (FFFFHH)
Size 13: 7,13 BAD (FFFFFF)
Size 14: 7,14 BAD (FFFFHH)
Size 15: 8,15 BAD (FFFFFF)
Size 16: 8,16 BAD (FFFFHH)
Size 17: 9,17 BAD (FFFFFF)
Size 18: 9,18 BAD (FFFFHH)
Size 19: 10,19 BAD (FFFFFF)
Size 20: 10,20 BAD (FFFFFF)
Size 21: 11,21 BAD (FFFFFF)
Size 22: 11,22 BAD (FFFFFF)
Size 23: 12,23 BAD (FFFFFF)
Size 24: 12,24 BAD (FFFFFF)
Size 25: 13,25 BAD (FFFFFF)
Size 26: 13,26 BAD (FFFFFF)
Size 27: 14,27 BAD (FFFFFF)
Size 28: 14,28 BAD (FFFFFF)
Size 29: 15,29 BAD (FFFFFF)
Size 30: 15,30 BAD (FFFFFF)
Size 31: 16,31 BAD (FFFFFF)
Size 32: 16,33 BAD (FFFFFF)
Size 33: 17,33 BAD (FFFFFF)
Size 34: 17,34 BAD (FFFFFF)
Size 35: 18,35 BAD (FFFFFF)
Size 36: 18,36 BAD (FFFFFF)
Size 37: 19,37 BAD (FFFFFF)
Size 38: 19,38 BAD (FFFFFF)
Size 39: 20,39 BAD (FFFFFF)
Size 40: 20,40 BAD (FFFFFF)
Size 41: 21,41 BAD (FFFFFF)
Size 42: 21,42 BAD (FFFFFF)
Size 43: 22,43 BAD (FFFFFF)
Size 44: 22,44 BAD (FFFFFF)
Size 45: 23,45 BAD (FFFFFF)
Size 46: 23,46 BAD (FFFFFF)
Size 47: 24,47 BAD (FFFFFF)
Size 48: 24,48 BAD (FFFFFF)
Size 49: 25,49 BAD (FFFFFF)
Size 50: 25,50 BAD (FFFFFF)
Size 51: 26,51 BAD (FFFFFF)
Size 52: 26,52 BAD (FFFFFF)
Size 53: 27,53 BAD (FFFFFF)
Size 54: 27,54 BAD (FFFFFF)
Size 55: 28,55 BAD (FFFFFF)
Size 56: 28,56 BAD (FFFFFF)
Size 57: 29,57 BAD (FFFFFF)
Size 58: 29,58 BAD (FFFFFF)
Size 59: 30,59 BAD (FFFFFF)
Size 60: 30,60 BAD (FFFFFF)
Size 61: 31,61 BAD (FFFFFF)
Size 62: 31,62 BAD (FFFFFF)
Size 63: 32,63 BAD (FFFFFF)
Size 64: 32,64 BAD (FFFFFF)
Size 65: 33,65 BAD (FFFFFF)
Size 66: 33,66 BAD (FFFFFF)
Size 67: 34,67 BAD (FFFFFF)
Size 68: 34,68 BAD (FFFFFF)
Size 69: 35,69 BAD (FFFFFF)
Size 70: 35,70 BAD (FFFFFF)
Size 71: 36,71 BAD (FFFFFF)
Size 72: 36,72 BAD (FFFFFF)
Size 73: 37,73 BAD (FFFFFF)
Size 74: 37,74 BAD (FFFFFF)
Size 75: 38,75 BAD (FFFFFF)
Size 76: 38,76 BAD (FFFFFF)
Size 77: 39,77 BAD (FFFFFF)
Size 78: 39,78 BAD (FFFFFF)
Size 79: 40,79 BAD (FFFFFF)
Size 80: 40,80 BAD (FFFFFF)
Size 81: 41,81 BAD (FFFFFF)
Size 82: 41,82 BAD (FFFFFF)
Size 83: 42,83 BAD (FFFFFF)
Size 84: 42,84 BAD (FFFFFF)
Size 85: 43,85 BAD (FFFFFF)
Size 86: 43,86 BAD (FFFFFF)
Size 87: 44,87 BAD (FFFFFF)
Size 88: 44,88 BAD (FFFFFF)
Size 89: 45,89 BAD (FFFFFF)
Size 90: 45,90 BAD (FFFFFF)
Size 91: 46,91 BAD (FFFFFF)
Size 92: 46,92 BAD (FFFFFF)
Size 93: 47,93 BAD (FFFFFF)
Size 94: 47,94 BAD (FFFFFF)
Size 95: 48,95 BAD (FFFFFF)
Size 96: 48,97 BAD (FFFFFF)
Size 97: 49,97 BAD (FFFFFF)
Size 98: 49,98 BAD (FFFFFF)
Size 99: 50,99 BAD (FFFFFF)
Size 100: 50,100 BAD (FFFFFF)
Windows 10 14342 New Console
----------------------------
Size 1: 1,1 OK (HHHFFF)
Size 2: 1,2 OK (HHHFFF)
Size 3: 2,3 OK (HHHFFF)
Size 4: 2,4 OK (HHHFFF)
Size 5: 3,5 OK (HHHFFF)
Size 6: 3,6 OK (HHHFFF)
Size 7: 4,7 OK (HHHFFF)
Size 8: 4,8 OK (HHHFFF)
Size 9: 5,9 OK (HHHFFF)
Size 10: 5,10 OK (HHHFFF)
Size 11: 6,11 OK (HHHFFF)
Size 12: 6,12 OK (HHHFFF)
Size 13: 7,13 OK (HHHFFF)
Size 14: 7,14 OK (HHHFFF)
Size 15: 8,15 OK (HHHFFF)
Size 16: 8,16 OK (HHHFFF)
Size 17: 9,17 OK (HHHFFF)
Size 18: 9,18 OK (HHHFFF)
Size 19: 10,19 OK (HHHFFF)
Size 20: 10,20 OK (HHHFFF)
Size 21: 11,21 OK (HHHFFF)
Size 22: 11,22 OK (HHHFFF)
Size 23: 12,23 OK (HHHFFF)
Size 24: 12,24 OK (HHHFFF)
Size 25: 13,25 OK (HHHFFF)
Size 26: 13,26 OK (HHHFFF)
Size 27: 14,27 OK (HHHFFF)
Size 28: 14,28 OK (HHHFFF)
Size 29: 15,29 OK (HHHFFF)
Size 30: 15,30 OK (HHHFFF)
Size 31: 16,31 OK (HHHFFF)
Size 32: 16,32 OK (HHHFFF)
Size 33: 17,33 OK (HHHFFF)
Size 34: 17,34 OK (HHHFFF)
Size 35: 18,35 OK (HHHFFF)
Size 36: 18,36 OK (HHHFFF)
Size 37: 19,37 OK (HHHFFF)
Size 38: 19,38 OK (HHHFFF)
Size 39: 20,39 OK (HHHFFF)
Size 40: 20,40 OK (HHHFFF)
Size 41: 21,41 OK (HHHFFF)
Size 42: 21,42 OK (HHHFFF)
Size 43: 22,43 OK (HHHFFF)
Size 44: 22,44 OK (HHHFFF)
Size 45: 23,45 OK (HHHFFF)
Size 46: 23,46 OK (HHHFFF)
Size 47: 24,47 OK (HHHFFF)
Size 48: 24,48 OK (HHHFFF)
Size 49: 25,49 OK (HHHFFF)
Size 50: 25,50 OK (HHHFFF)
Size 51: 26,51 OK (HHHFFF)
Size 52: 26,52 OK (HHHFFF)
Size 53: 27,53 OK (HHHFFF)
Size 54: 27,54 OK (HHHFFF)
Size 55: 28,55 OK (HHHFFF)
Size 56: 28,56 OK (HHHFFF)
Size 57: 29,57 OK (HHHFFF)
Size 58: 29,58 OK (HHHFFF)
Size 59: 30,59 OK (HHHFFF)
Size 60: 30,60 OK (HHHFFF)
Size 61: 31,61 OK (HHHFFF)
Size 62: 31,62 OK (HHHFFF)
Size 63: 32,63 OK (HHHFFF)
Size 64: 32,64 OK (HHHFFF)
Size 65: 33,65 OK (HHHFFF)
Size 66: 33,66 OK (HHHFFF)
Size 67: 34,67 OK (HHHFFF)
Size 68: 34,68 OK (HHHFFF)
Size 69: 35,69 OK (HHHFFF)
Size 70: 35,70 OK (HHHFFF)
Size 71: 36,71 OK (HHHFFF)
Size 72: 36,72 OK (HHHFFF)
Size 73: 37,73 OK (HHHFFF)
Size 74: 37,74 OK (HHHFFF)
Size 75: 38,75 OK (HHHFFF)
Size 76: 38,76 OK (HHHFFF)
Size 77: 39,77 OK (HHHFFF)
Size 78: 39,78 OK (HHHFFF)
Size 79: 40,79 OK (HHHFFF)
Size 80: 40,80 OK (HHHFFF)
Size 81: 41,81 OK (HHHFFF)
Size 82: 41,82 OK (HHHFFF)
Size 83: 42,83 OK (HHHFFF)
Size 84: 42,84 OK (HHHFFF)
Size 85: 43,85 OK (HHHFFF)
Size 86: 43,86 OK (HHHFFF)
Size 87: 44,87 OK (HHHFFF)
Size 88: 44,88 OK (HHHFFF)
Size 89: 45,89 OK (HHHFFF)
Size 90: 45,90 OK (HHHFFF)
Size 91: 46,91 OK (HHHFFF)
Size 92: 46,92 OK (HHHFFF)
Size 93: 47,93 OK (HHHFFF)
Size 94: 47,94 OK (HHHFFF)
Size 95: 48,95 OK (HHHFFF)
Size 96: 48,96 OK (HHHFFF)
Size 97: 49,97 OK (HHHFFF)
Size 98: 49,98 OK (HHHFFF)
Size 99: 50,99 OK (HHHFFF)
Size 100: 50,100 OK (HHHFFF)

View File

@@ -0,0 +1,630 @@
==========================================================
Code Page 936, Chinese Simplified (China/PRC), SimSun font
==========================================================
Options: -face-simsun -family 0x36
Chars: A2 A3 2014 3044 30FC 4000
Vista
-----
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,3 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (HHHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (HHHFHH)
Size 8: 4,9 GOOD (HHFFFF)
Size 9: 5,10 BAD (HHHFHH)
Size 10: 5,11 GOOD (HHFFFF)
Size 11: 6,13 BAD (HHHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,15 BAD (HHHFHH)
Size 14: 7,16 GOOD (HHFFFF)
Size 15: 8,17 BAD (HHHFHH)
Size 16: 8,18 GOOD (HHFFFF)
Size 17: 9,19 BAD (HHHFHH)
Size 18: 9,21 GOOD (HHFFFF)
Size 19: 10,22 BAD (HHHFHH)
Size 20: 10,23 GOOD (HHFFFF)
Size 21: 11,24 BAD (HHHFHH)
Size 22: 11,25 GOOD (HHFFFF)
Size 23: 12,26 BAD (HHHFHH)
Size 24: 12,27 GOOD (HHFFFF)
Size 25: 13,29 BAD (HHHFHH)
Size 26: 13,30 GOOD (HHFFFF)
Size 27: 14,31 BAD (HHHFHH)
Size 28: 14,32 GOOD (HHFFFF)
Size 29: 15,33 BAD (HHHFHH)
Size 30: 15,34 GOOD (HHFFFF)
Size 31: 16,35 BAD (HHHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,38 BAD (HHHFHH)
Size 34: 17,39 GOOD (HHFFFF)
Size 35: 18,40 BAD (HHHFHH)
Size 36: 18,41 GOOD (HHFFFF)
Size 37: 19,42 BAD (HHHFHH)
Size 38: 19,43 GOOD (HHFFFF)
Size 39: 20,44 BAD (HHHFHH)
Size 40: 20,46 GOOD (HHFFFF)
Size 41: 21,47 BAD (HHHFHH)
Size 42: 21,48 GOOD (HHFFFF)
Size 43: 22,49 BAD (HHHFHH)
Size 44: 22,50 GOOD (HHFFFF)
Size 45: 23,51 BAD (HHHFHH)
Size 46: 23,52 GOOD (HHFFFF)
Size 47: 24,54 BAD (HHHFHH)
Size 48: 24,55 GOOD (HHFFFF)
Size 49: 25,56 BAD (HHHFHH)
Size 50: 25,57 GOOD (HHFFFF)
Size 51: 26,58 BAD (HHHFHH)
Size 52: 26,59 GOOD (HHFFFF)
Size 53: 27,60 BAD (HHHFHH)
Size 54: 27,62 GOOD (HHFFFF)
Size 55: 28,63 BAD (HHHFHH)
Size 56: 28,64 GOOD (HHFFFF)
Size 57: 29,65 BAD (HHHFHH)
Size 58: 29,66 GOOD (HHFFFF)
Size 59: 30,67 BAD (HHHFHH)
Size 60: 30,68 GOOD (HHFFFF)
Size 61: 31,70 BAD (HHHFHH)
Size 62: 31,71 GOOD (HHFFFF)
Size 63: 32,72 BAD (HHHFHH)
Size 64: 32,73 GOOD (HHFFFF)
Size 65: 33,74 GOOD (HHFFFF)
Size 66: 33,75 GOOD (HHFFFF)
Size 67: 34,76 GOOD (HHFFFF)
Size 68: 34,78 GOOD (HHFFFF)
Size 69: 35,79 GOOD (HHFFFF)
Size 70: 35,80 GOOD (HHFFFF)
Size 71: 36,81 GOOD (HHFFFF)
Size 72: 36,82 GOOD (HHFFFF)
Size 73: 37,83 GOOD (HHFFFF)
Size 74: 37,84 GOOD (HHFFFF)
Size 75: 38,86 GOOD (HHFFFF)
Size 76: 38,87 GOOD (HHFFFF)
Size 77: 39,88 GOOD (HHFFFF)
Size 78: 39,89 GOOD (HHFFFF)
Size 79: 40,90 GOOD (HHFFFF)
Size 80: 40,91 GOOD (HHFFFF)
Size 81: 41,92 GOOD (HHFFFF)
Size 82: 41,94 GOOD (HHFFFF)
Size 83: 42,95 GOOD (HHFFFF)
Size 84: 42,96 GOOD (HHFFFF)
Size 85: 43,97 GOOD (HHFFFF)
Size 86: 43,98 GOOD (HHFFFF)
Size 87: 44,99 GOOD (HHFFFF)
Size 88: 44,100 GOOD (HHFFFF)
Size 89: 45,102 GOOD (HHFFFF)
Size 90: 45,103 GOOD (HHFFFF)
Size 91: 46,104 GOOD (HHFFFF)
Size 92: 46,105 GOOD (HHFFFF)
Size 93: 47,106 GOOD (HHFFFF)
Size 94: 47,107 GOOD (HHFFFF)
Size 95: 48,108 GOOD (HHFFFF)
Size 96: 48,111 GOOD (HHFFFF)
Size 97: 49,111 GOOD (HHFFFF)
Size 98: 49,112 GOOD (HHFFFF)
Size 99: 50,113 GOOD (HHFFFF)
Size 100: 50,114 GOOD (HHFFFF)
Windows 7
---------
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,3 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (FFHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (FFHFHH)
Size 8: 4,9 GOOD (HHFFFF)
Size 9: 5,10 BAD (FFHFHH)
Size 10: 5,11 GOOD (HHFFFF)
Size 11: 6,13 BAD (FFHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,15 BAD (FFHFHH)
Size 14: 7,16 GOOD (HHFFFF)
Size 15: 8,17 BAD (FFHFHH)
Size 16: 8,18 GOOD (HHFFFF)
Size 17: 9,19 BAD (FFHFHH)
Size 18: 9,21 GOOD (HHFFFF)
Size 19: 10,22 BAD (FFHFHH)
Size 20: 10,23 GOOD (HHFFFF)
Size 21: 11,24 BAD (FFHFHH)
Size 22: 11,25 GOOD (HHFFFF)
Size 23: 12,26 BAD (FFHFHH)
Size 24: 12,27 GOOD (HHFFFF)
Size 25: 13,29 BAD (FFHFHH)
Size 26: 13,30 GOOD (HHFFFF)
Size 27: 14,31 BAD (FFHFHH)
Size 28: 14,32 GOOD (HHFFFF)
Size 29: 15,33 BAD (FFHFHH)
Size 30: 15,34 GOOD (HHFFFF)
Size 31: 16,35 BAD (FFHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,38 BAD (FFHFHH)
Size 34: 17,39 GOOD (HHFFFF)
Size 35: 18,40 BAD (FFHFHH)
Size 36: 18,41 GOOD (HHFFFF)
Size 37: 19,42 BAD (FFHFHH)
Size 38: 19,43 GOOD (HHFFFF)
Size 39: 20,44 BAD (FFHFHH)
Size 40: 20,46 GOOD (HHFFFF)
Size 41: 21,47 BAD (FFHFHH)
Size 42: 21,48 GOOD (HHFFFF)
Size 43: 22,49 BAD (FFHFHH)
Size 44: 22,50 GOOD (HHFFFF)
Size 45: 23,51 BAD (FFHFHH)
Size 46: 23,52 GOOD (HHFFFF)
Size 47: 24,54 BAD (FFHFHH)
Size 48: 24,55 GOOD (HHFFFF)
Size 49: 25,56 BAD (FFHFHH)
Size 50: 25,57 GOOD (HHFFFF)
Size 51: 26,58 BAD (FFHFHH)
Size 52: 26,59 GOOD (HHFFFF)
Size 53: 27,60 BAD (FFHFHH)
Size 54: 27,62 GOOD (HHFFFF)
Size 55: 28,63 BAD (FFHFHH)
Size 56: 28,64 GOOD (HHFFFF)
Size 57: 29,65 BAD (FFHFHH)
Size 58: 29,66 GOOD (HHFFFF)
Size 59: 30,67 BAD (FFHFHH)
Size 60: 30,68 GOOD (HHFFFF)
Size 61: 31,70 BAD (FFHFHH)
Size 62: 31,71 GOOD (HHFFFF)
Size 63: 32,72 BAD (FFHFHH)
Size 64: 32,73 GOOD (HHFFFF)
Size 65: 33,74 GOOD (HHFFFF)
Size 66: 33,75 GOOD (HHFFFF)
Size 67: 34,76 GOOD (HHFFFF)
Size 68: 34,78 GOOD (HHFFFF)
Size 69: 35,79 GOOD (HHFFFF)
Size 70: 35,80 GOOD (HHFFFF)
Size 71: 36,81 GOOD (HHFFFF)
Size 72: 36,82 GOOD (HHFFFF)
Size 73: 37,83 GOOD (HHFFFF)
Size 74: 37,84 GOOD (HHFFFF)
Size 75: 38,86 GOOD (HHFFFF)
Size 76: 38,87 GOOD (HHFFFF)
Size 77: 39,88 GOOD (HHFFFF)
Size 78: 39,89 GOOD (HHFFFF)
Size 79: 40,90 GOOD (HHFFFF)
Size 80: 40,91 GOOD (HHFFFF)
Size 81: 41,92 GOOD (HHFFFF)
Size 82: 41,94 GOOD (HHFFFF)
Size 83: 42,95 GOOD (HHFFFF)
Size 84: 42,96 GOOD (HHFFFF)
Size 85: 43,97 GOOD (HHFFFF)
Size 86: 43,98 GOOD (HHFFFF)
Size 87: 44,99 GOOD (HHFFFF)
Size 88: 44,100 GOOD (HHFFFF)
Size 89: 45,102 GOOD (HHFFFF)
Size 90: 45,103 GOOD (HHFFFF)
Size 91: 46,104 GOOD (HHFFFF)
Size 92: 46,105 GOOD (HHFFFF)
Size 93: 47,106 GOOD (HHFFFF)
Size 94: 47,107 GOOD (HHFFFF)
Size 95: 48,108 GOOD (HHFFFF)
Size 96: 48,111 GOOD (HHFFFF)
Size 97: 49,111 GOOD (HHFFFF)
Size 98: 49,112 GOOD (HHFFFF)
Size 99: 50,113 GOOD (HHFFFF)
Size 100: 50,114 GOOD (HHFFFF)
Windows 8
---------
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,3 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (FFHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (FFHFHH)
Size 8: 4,9 GOOD (HHFFFF)
Size 9: 5,10 BAD (FFHFHH)
Size 10: 5,11 GOOD (HHFFFF)
Size 11: 6,13 BAD (FFHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,15 BAD (FFHFHH)
Size 14: 7,16 GOOD (HHFFFF)
Size 15: 8,17 BAD (FFHFHH)
Size 16: 8,18 GOOD (HHFFFF)
Size 17: 9,19 BAD (FFHFHH)
Size 18: 9,21 GOOD (HHFFFF)
Size 19: 10,22 BAD (FFHFHH)
Size 20: 10,23 GOOD (HHFFFF)
Size 21: 11,24 BAD (FFHFHH)
Size 22: 11,25 GOOD (HHFFFF)
Size 23: 12,26 BAD (FFHFHH)
Size 24: 12,27 GOOD (HHFFFF)
Size 25: 13,29 BAD (FFHFHH)
Size 26: 13,30 GOOD (HHFFFF)
Size 27: 14,31 BAD (FFHFHH)
Size 28: 14,32 GOOD (HHFFFF)
Size 29: 15,33 BAD (FFHFHH)
Size 30: 15,34 GOOD (HHFFFF)
Size 31: 16,35 BAD (FFHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,38 BAD (FFHFHH)
Size 34: 17,39 GOOD (HHFFFF)
Size 35: 18,40 BAD (FFHFHH)
Size 36: 18,41 GOOD (HHFFFF)
Size 37: 19,42 BAD (FFHFHH)
Size 38: 19,43 GOOD (HHFFFF)
Size 39: 20,44 BAD (FFHFHH)
Size 40: 20,46 GOOD (HHFFFF)
Size 41: 21,47 BAD (FFHFHH)
Size 42: 21,48 GOOD (HHFFFF)
Size 43: 22,49 BAD (FFHFHH)
Size 44: 22,50 GOOD (HHFFFF)
Size 45: 23,51 BAD (FFHFHH)
Size 46: 23,52 GOOD (HHFFFF)
Size 47: 24,54 BAD (FFHFHH)
Size 48: 24,55 GOOD (HHFFFF)
Size 49: 25,56 BAD (FFHFHH)
Size 50: 25,57 GOOD (HHFFFF)
Size 51: 26,58 BAD (FFHFHH)
Size 52: 26,59 GOOD (HHFFFF)
Size 53: 27,60 BAD (FFHFHH)
Size 54: 27,62 GOOD (HHFFFF)
Size 55: 28,63 BAD (FFHFHH)
Size 56: 28,64 GOOD (HHFFFF)
Size 57: 29,65 BAD (FFHFHH)
Size 58: 29,66 GOOD (HHFFFF)
Size 59: 30,67 BAD (FFHFHH)
Size 60: 30,68 GOOD (HHFFFF)
Size 61: 31,70 BAD (FFHFHH)
Size 62: 31,71 GOOD (HHFFFF)
Size 63: 32,72 BAD (FFHFHH)
Size 64: 32,73 GOOD (HHFFFF)
Size 65: 33,74 GOOD (HHFFFF)
Size 66: 33,75 GOOD (HHFFFF)
Size 67: 34,76 GOOD (HHFFFF)
Size 68: 34,78 GOOD (HHFFFF)
Size 69: 35,79 GOOD (HHFFFF)
Size 70: 35,80 GOOD (HHFFFF)
Size 71: 36,81 GOOD (HHFFFF)
Size 72: 36,82 GOOD (HHFFFF)
Size 73: 37,83 GOOD (HHFFFF)
Size 74: 37,84 GOOD (HHFFFF)
Size 75: 38,86 GOOD (HHFFFF)
Size 76: 38,87 GOOD (HHFFFF)
Size 77: 39,88 GOOD (HHFFFF)
Size 78: 39,89 GOOD (HHFFFF)
Size 79: 40,90 GOOD (HHFFFF)
Size 80: 40,91 GOOD (HHFFFF)
Size 81: 41,92 GOOD (HHFFFF)
Size 82: 41,94 GOOD (HHFFFF)
Size 83: 42,95 GOOD (HHFFFF)
Size 84: 42,96 GOOD (HHFFFF)
Size 85: 43,97 GOOD (HHFFFF)
Size 86: 43,98 GOOD (HHFFFF)
Size 87: 44,99 GOOD (HHFFFF)
Size 88: 44,100 GOOD (HHFFFF)
Size 89: 45,102 GOOD (HHFFFF)
Size 90: 45,103 GOOD (HHFFFF)
Size 91: 46,104 GOOD (HHFFFF)
Size 92: 46,105 GOOD (HHFFFF)
Size 93: 47,106 GOOD (HHFFFF)
Size 94: 47,107 GOOD (HHFFFF)
Size 95: 48,108 GOOD (HHFFFF)
Size 96: 48,111 GOOD (HHFFFF)
Size 97: 49,111 GOOD (HHFFFF)
Size 98: 49,112 GOOD (HHFFFF)
Size 99: 50,113 GOOD (HHFFFF)
Size 100: 50,114 GOOD (HHFFFF)
Windows 8.1
-----------
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,3 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (FFHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (FFHFHH)
Size 8: 4,9 GOOD (HHFFFF)
Size 9: 5,10 BAD (FFHFHH)
Size 10: 5,11 GOOD (HHFFFF)
Size 11: 6,13 BAD (FFHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,15 BAD (FFHFHH)
Size 14: 7,16 GOOD (HHFFFF)
Size 15: 8,17 BAD (FFHFHH)
Size 16: 8,18 GOOD (HHFFFF)
Size 17: 9,19 BAD (FFHFHH)
Size 18: 9,21 GOOD (HHFFFF)
Size 19: 10,22 BAD (FFHFHH)
Size 20: 10,23 GOOD (HHFFFF)
Size 21: 11,24 BAD (FFHFHH)
Size 22: 11,25 GOOD (HHFFFF)
Size 23: 12,26 BAD (FFHFHH)
Size 24: 12,27 GOOD (HHFFFF)
Size 25: 13,29 BAD (FFHFHH)
Size 26: 13,30 GOOD (HHFFFF)
Size 27: 14,31 BAD (FFHFHH)
Size 28: 14,32 GOOD (HHFFFF)
Size 29: 15,33 BAD (FFHFHH)
Size 30: 15,34 GOOD (HHFFFF)
Size 31: 16,35 BAD (FFHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,38 BAD (FFHFHH)
Size 34: 17,39 GOOD (HHFFFF)
Size 35: 18,40 BAD (FFHFHH)
Size 36: 18,41 GOOD (HHFFFF)
Size 37: 19,42 BAD (FFHFHH)
Size 38: 19,43 GOOD (HHFFFF)
Size 39: 20,44 BAD (FFHFHH)
Size 40: 20,46 GOOD (HHFFFF)
Size 41: 21,47 BAD (FFHFHH)
Size 42: 21,48 GOOD (HHFFFF)
Size 43: 22,49 BAD (FFHFHH)
Size 44: 22,50 GOOD (HHFFFF)
Size 45: 23,51 BAD (FFHFHH)
Size 46: 23,52 GOOD (HHFFFF)
Size 47: 24,54 BAD (FFHFHH)
Size 48: 24,55 GOOD (HHFFFF)
Size 49: 25,56 BAD (FFHFHH)
Size 50: 25,57 GOOD (HHFFFF)
Size 51: 26,58 BAD (FFHFHH)
Size 52: 26,59 GOOD (HHFFFF)
Size 53: 27,60 BAD (FFHFHH)
Size 54: 27,62 GOOD (HHFFFF)
Size 55: 28,63 BAD (FFHFHH)
Size 56: 28,64 GOOD (HHFFFF)
Size 57: 29,65 BAD (FFHFHH)
Size 58: 29,66 GOOD (HHFFFF)
Size 59: 30,67 BAD (FFHFHH)
Size 60: 30,68 GOOD (HHFFFF)
Size 61: 31,70 BAD (FFHFHH)
Size 62: 31,71 GOOD (HHFFFF)
Size 63: 32,72 BAD (FFHFHH)
Size 64: 32,73 GOOD (HHFFFF)
Size 65: 33,74 GOOD (HHFFFF)
Size 66: 33,75 GOOD (HHFFFF)
Size 67: 34,76 GOOD (HHFFFF)
Size 68: 34,78 GOOD (HHFFFF)
Size 69: 35,79 GOOD (HHFFFF)
Size 70: 35,80 GOOD (HHFFFF)
Size 71: 36,81 GOOD (HHFFFF)
Size 72: 36,82 GOOD (HHFFFF)
Size 73: 37,83 GOOD (HHFFFF)
Size 74: 37,84 GOOD (HHFFFF)
Size 75: 38,86 GOOD (HHFFFF)
Size 76: 38,87 GOOD (HHFFFF)
Size 77: 39,88 GOOD (HHFFFF)
Size 78: 39,89 GOOD (HHFFFF)
Size 79: 40,90 GOOD (HHFFFF)
Size 80: 40,91 GOOD (HHFFFF)
Size 81: 41,92 GOOD (HHFFFF)
Size 82: 41,94 GOOD (HHFFFF)
Size 83: 42,95 GOOD (HHFFFF)
Size 84: 42,96 GOOD (HHFFFF)
Size 85: 43,97 GOOD (HHFFFF)
Size 86: 43,98 GOOD (HHFFFF)
Size 87: 44,99 GOOD (HHFFFF)
Size 88: 44,100 GOOD (HHFFFF)
Size 89: 45,102 GOOD (HHFFFF)
Size 90: 45,103 GOOD (HHFFFF)
Size 91: 46,104 GOOD (HHFFFF)
Size 92: 46,105 GOOD (HHFFFF)
Size 93: 47,106 GOOD (HHFFFF)
Size 94: 47,107 GOOD (HHFFFF)
Size 95: 48,108 GOOD (HHFFFF)
Size 96: 48,111 GOOD (HHFFFF)
Size 97: 49,111 GOOD (HHFFFF)
Size 98: 49,112 GOOD (HHFFFF)
Size 99: 50,113 GOOD (HHFFFF)
Size 100: 50,114 GOOD (HHFFFF)
Windows 10 14342 Old Console
----------------------------
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,3 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (FFHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (FFHFHH)
Size 8: 4,9 GOOD (HHFFFF)
Size 9: 5,10 BAD (FFHFHH)
Size 10: 5,11 GOOD (HHFFFF)
Size 11: 6,13 BAD (FFHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,15 BAD (FFHFHH)
Size 14: 7,16 GOOD (HHFFFF)
Size 15: 8,17 BAD (FFHFHH)
Size 16: 8,18 GOOD (HHFFFF)
Size 17: 9,19 BAD (FFHFHH)
Size 18: 9,21 GOOD (HHFFFF)
Size 19: 10,22 BAD (FFHFHH)
Size 20: 10,23 GOOD (HHFFFF)
Size 21: 11,24 BAD (FFHFHH)
Size 22: 11,25 GOOD (HHFFFF)
Size 23: 12,26 BAD (FFHFHH)
Size 24: 12,27 GOOD (HHFFFF)
Size 25: 13,29 BAD (FFHFHH)
Size 26: 13,30 GOOD (HHFFFF)
Size 27: 14,31 BAD (FFHFHH)
Size 28: 14,32 GOOD (HHFFFF)
Size 29: 15,33 BAD (FFHFHH)
Size 30: 15,34 GOOD (HHFFFF)
Size 31: 16,35 BAD (FFHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,38 BAD (FFHFHH)
Size 34: 17,39 GOOD (HHFFFF)
Size 35: 18,40 BAD (FFHFHH)
Size 36: 18,41 GOOD (HHFFFF)
Size 37: 19,42 BAD (FFHFHH)
Size 38: 19,43 GOOD (HHFFFF)
Size 39: 20,44 BAD (FFHFHH)
Size 40: 20,46 GOOD (HHFFFF)
Size 41: 21,47 BAD (FFHFHH)
Size 42: 21,48 GOOD (HHFFFF)
Size 43: 22,49 BAD (FFHFHH)
Size 44: 22,50 GOOD (HHFFFF)
Size 45: 23,51 BAD (FFHFHH)
Size 46: 23,52 GOOD (HHFFFF)
Size 47: 24,54 BAD (FFHFHH)
Size 48: 24,55 GOOD (HHFFFF)
Size 49: 25,56 BAD (FFHFHH)
Size 50: 25,57 GOOD (HHFFFF)
Size 51: 26,58 BAD (FFHFHH)
Size 52: 26,59 GOOD (HHFFFF)
Size 53: 27,60 BAD (FFHFHH)
Size 54: 27,62 GOOD (HHFFFF)
Size 55: 28,63 BAD (FFHFHH)
Size 56: 28,64 GOOD (HHFFFF)
Size 57: 29,65 BAD (FFHFHH)
Size 58: 29,66 GOOD (HHFFFF)
Size 59: 30,67 BAD (FFHFHH)
Size 60: 30,68 GOOD (HHFFFF)
Size 61: 31,70 BAD (FFHFHH)
Size 62: 31,71 GOOD (HHFFFF)
Size 63: 32,72 BAD (FFHFHH)
Size 64: 32,73 GOOD (HHFFFF)
Size 65: 33,74 GOOD (HHFFFF)
Size 66: 33,75 GOOD (HHFFFF)
Size 67: 34,76 GOOD (HHFFFF)
Size 68: 34,78 GOOD (HHFFFF)
Size 69: 35,79 GOOD (HHFFFF)
Size 70: 35,80 GOOD (HHFFFF)
Size 71: 36,81 GOOD (HHFFFF)
Size 72: 36,82 GOOD (HHFFFF)
Size 73: 37,83 GOOD (HHFFFF)
Size 74: 37,84 GOOD (HHFFFF)
Size 75: 38,86 GOOD (HHFFFF)
Size 76: 38,87 GOOD (HHFFFF)
Size 77: 39,88 GOOD (HHFFFF)
Size 78: 39,89 GOOD (HHFFFF)
Size 79: 40,90 GOOD (HHFFFF)
Size 80: 40,91 GOOD (HHFFFF)
Size 81: 41,92 GOOD (HHFFFF)
Size 82: 41,94 GOOD (HHFFFF)
Size 83: 42,95 GOOD (HHFFFF)
Size 84: 42,96 GOOD (HHFFFF)
Size 85: 43,97 GOOD (HHFFFF)
Size 86: 43,98 GOOD (HHFFFF)
Size 87: 44,99 GOOD (HHFFFF)
Size 88: 44,100 GOOD (HHFFFF)
Size 89: 45,102 GOOD (HHFFFF)
Size 90: 45,103 GOOD (HHFFFF)
Size 91: 46,104 GOOD (HHFFFF)
Size 92: 46,105 GOOD (HHFFFF)
Size 93: 47,106 GOOD (HHFFFF)
Size 94: 47,107 GOOD (HHFFFF)
Size 95: 48,108 GOOD (HHFFFF)
Size 96: 48,111 GOOD (HHFFFF)
Size 97: 49,111 GOOD (HHFFFF)
Size 98: 49,112 GOOD (HHFFFF)
Size 99: 50,113 GOOD (HHFFFF)
Size 100: 50,114 GOOD (HHFFFF)
Windows 10 14342 New Console
----------------------------
Size 1: 1,1 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,3 GOOD (HHFFFF)
Size 4: 2,4 GOOD (HHFFFF)
Size 5: 3,5 GOOD (HHFFFF)
Size 6: 3,6 GOOD (HHFFFF)
Size 7: 4,7 GOOD (HHFFFF)
Size 8: 4,8 GOOD (HHFFFF)
Size 9: 5,9 GOOD (HHFFFF)
Size 10: 5,10 GOOD (HHFFFF)
Size 11: 6,11 GOOD (HHFFFF)
Size 12: 6,12 GOOD (HHFFFF)
Size 13: 7,13 GOOD (HHFFFF)
Size 14: 7,14 GOOD (HHFFFF)
Size 15: 8,15 GOOD (HHFFFF)
Size 16: 8,16 GOOD (HHFFFF)
Size 17: 9,17 GOOD (HHFFFF)
Size 18: 9,18 GOOD (HHFFFF)
Size 19: 10,19 GOOD (HHFFFF)
Size 20: 10,20 GOOD (HHFFFF)
Size 21: 11,21 GOOD (HHFFFF)
Size 22: 11,22 GOOD (HHFFFF)
Size 23: 12,23 GOOD (HHFFFF)
Size 24: 12,24 GOOD (HHFFFF)
Size 25: 13,25 GOOD (HHFFFF)
Size 26: 13,26 GOOD (HHFFFF)
Size 27: 14,27 GOOD (HHFFFF)
Size 28: 14,28 GOOD (HHFFFF)
Size 29: 15,29 GOOD (HHFFFF)
Size 30: 15,30 GOOD (HHFFFF)
Size 31: 16,31 GOOD (HHFFFF)
Size 32: 16,32 GOOD (HHFFFF)
Size 33: 17,33 GOOD (HHFFFF)
Size 34: 17,34 GOOD (HHFFFF)
Size 35: 18,35 GOOD (HHFFFF)
Size 36: 18,36 GOOD (HHFFFF)
Size 37: 19,37 GOOD (HHFFFF)
Size 38: 19,38 GOOD (HHFFFF)
Size 39: 20,39 GOOD (HHFFFF)
Size 40: 20,40 GOOD (HHFFFF)
Size 41: 21,41 GOOD (HHFFFF)
Size 42: 21,42 GOOD (HHFFFF)
Size 43: 22,43 GOOD (HHFFFF)
Size 44: 22,44 GOOD (HHFFFF)
Size 45: 23,45 GOOD (HHFFFF)
Size 46: 23,46 GOOD (HHFFFF)
Size 47: 24,47 GOOD (HHFFFF)
Size 48: 24,48 GOOD (HHFFFF)
Size 49: 25,49 GOOD (HHFFFF)
Size 50: 25,50 GOOD (HHFFFF)
Size 51: 26,51 GOOD (HHFFFF)
Size 52: 26,52 GOOD (HHFFFF)
Size 53: 27,53 GOOD (HHFFFF)
Size 54: 27,54 GOOD (HHFFFF)
Size 55: 28,55 GOOD (HHFFFF)
Size 56: 28,56 GOOD (HHFFFF)
Size 57: 29,57 GOOD (HHFFFF)
Size 58: 29,58 GOOD (HHFFFF)
Size 59: 30,59 GOOD (HHFFFF)
Size 60: 30,60 GOOD (HHFFFF)
Size 61: 31,61 GOOD (HHFFFF)
Size 62: 31,62 GOOD (HHFFFF)
Size 63: 32,63 GOOD (HHFFFF)
Size 64: 32,64 GOOD (HHFFFF)
Size 65: 33,65 GOOD (HHFFFF)
Size 66: 33,66 GOOD (HHFFFF)
Size 67: 34,67 GOOD (HHFFFF)
Size 68: 34,68 GOOD (HHFFFF)
Size 69: 35,69 GOOD (HHFFFF)
Size 70: 35,70 GOOD (HHFFFF)
Size 71: 36,71 GOOD (HHFFFF)
Size 72: 36,72 GOOD (HHFFFF)
Size 73: 37,73 GOOD (HHFFFF)
Size 74: 37,74 GOOD (HHFFFF)
Size 75: 38,75 GOOD (HHFFFF)
Size 76: 38,76 GOOD (HHFFFF)
Size 77: 39,77 GOOD (HHFFFF)
Size 78: 39,78 GOOD (HHFFFF)
Size 79: 40,79 GOOD (HHFFFF)
Size 80: 40,80 GOOD (HHFFFF)
Size 81: 41,81 GOOD (HHFFFF)
Size 82: 41,82 GOOD (HHFFFF)
Size 83: 42,83 GOOD (HHFFFF)
Size 84: 42,84 GOOD (HHFFFF)
Size 85: 43,85 GOOD (HHFFFF)
Size 86: 43,86 GOOD (HHFFFF)
Size 87: 44,87 GOOD (HHFFFF)
Size 88: 44,88 GOOD (HHFFFF)
Size 89: 45,89 GOOD (HHFFFF)
Size 90: 45,90 GOOD (HHFFFF)
Size 91: 46,91 GOOD (HHFFFF)
Size 92: 46,92 GOOD (HHFFFF)
Size 93: 47,93 GOOD (HHFFFF)
Size 94: 47,94 GOOD (HHFFFF)
Size 95: 48,95 GOOD (HHFFFF)
Size 96: 48,96 GOOD (HHFFFF)
Size 97: 49,97 GOOD (HHFFFF)
Size 98: 49,98 GOOD (HHFFFF)
Size 99: 50,99 GOOD (HHFFFF)
Size 100: 50,100 GOOD (HHFFFF)

View File

@@ -0,0 +1,630 @@
=====================================
Code Page 949, Korean, GulimChe font
=====================================
Options: -face-gulimche -family 0x36
Chars: A2 A3 2014 3044 30FC 4000
Vista
-----
Size 1: 1,2 OK (HHHFFF)
Size 2: 1,2 OK (HHHFFF)
Size 3: 2,3 BAD (FFFFHH)
Size 4: 2,5 OK (HHHFFF)
Size 5: 3,6 BAD (HHHFHH)
Size 6: 3,7 OK (HHHFFF)
Size 7: 4,8 BAD (HHHFHH)
Size 8: 4,9 OK (HHHFFF)
Size 9: 5,10 BAD (HHHFHH)
Size 10: 5,11 OK (HHHFFF)
Size 11: 6,13 BAD (HHHFHH)
Size 12: 6,14 OK (HHHFFF)
Size 13: 7,15 BAD (HHHFHH)
Size 14: 7,16 OK (HHHFFF)
Size 15: 8,17 BAD (HHHFHH)
Size 16: 8,18 OK (HHHFFF)
Size 17: 9,20 BAD (HHHFHH)
Size 18: 9,21 OK (HHHFFF)
Size 19: 10,22 BAD (HHHFHH)
Size 20: 10,23 OK (HHHFFF)
Size 21: 11,24 BAD (HHHFHH)
Size 22: 11,25 OK (HHHFFF)
Size 23: 12,26 BAD (HHHFHH)
Size 24: 12,28 OK (HHHFFF)
Size 25: 13,29 BAD (HHHFHH)
Size 26: 13,30 OK (HHHFFF)
Size 27: 14,31 BAD (HHHFHH)
Size 28: 14,32 OK (HHHFFF)
Size 29: 15,33 BAD (HHHFHH)
Size 30: 15,34 OK (HHHFFF)
Size 31: 16,36 BAD (HHHFHH)
Size 32: 16,37 OK (HHHFFF)
Size 33: 17,38 BAD (HHHFHH)
Size 34: 17,39 OK (HHHFFF)
Size 35: 18,40 BAD (HHHFHH)
Size 36: 18,41 OK (HHHFFF)
Size 37: 19,42 BAD (HHHFHH)
Size 38: 19,44 OK (HHHFFF)
Size 39: 20,45 BAD (HHHFHH)
Size 40: 20,46 OK (HHHFFF)
Size 41: 21,47 BAD (HHHFHH)
Size 42: 21,48 OK (HHHFFF)
Size 43: 22,49 BAD (HHHFHH)
Size 44: 22,51 OK (HHHFFF)
Size 45: 23,52 BAD (HHHFHH)
Size 46: 23,53 OK (HHHFFF)
Size 47: 24,54 BAD (HHHFHH)
Size 48: 24,55 OK (HHHFFF)
Size 49: 25,56 BAD (HHHFHH)
Size 50: 25,57 OK (HHHFFF)
Size 51: 26,59 BAD (HHHFHH)
Size 52: 26,60 OK (HHHFFF)
Size 53: 27,61 BAD (HHHFHH)
Size 54: 27,62 OK (HHHFFF)
Size 55: 28,63 BAD (HHHFHH)
Size 56: 28,64 OK (HHHFFF)
Size 57: 29,65 BAD (HHHFHH)
Size 58: 29,67 OK (HHHFFF)
Size 59: 30,68 BAD (HHHFHH)
Size 60: 30,69 OK (HHHFFF)
Size 61: 31,70 BAD (HHHFHH)
Size 62: 31,71 OK (HHHFFF)
Size 63: 32,72 BAD (HHHFHH)
Size 64: 32,74 OK (HHHFFF)
Size 65: 33,75 BAD (HHHFHH)
Size 66: 33,76 OK (HHHFFF)
Size 67: 34,77 BAD (HHHFHH)
Size 68: 34,78 OK (HHHFFF)
Size 69: 35,79 BAD (HHHFHH)
Size 70: 35,80 OK (HHHFFF)
Size 71: 36,82 BAD (HHHFHH)
Size 72: 36,83 OK (HHHFFF)
Size 73: 37,84 BAD (HHHFHH)
Size 74: 37,85 OK (HHHFFF)
Size 75: 38,86 BAD (HHHFHH)
Size 76: 38,87 OK (HHHFFF)
Size 77: 39,88 BAD (HHHFHH)
Size 78: 39,90 OK (HHHFFF)
Size 79: 40,91 BAD (HHHFHH)
Size 80: 40,92 OK (HHHFFF)
Size 81: 41,93 BAD (HHHFHH)
Size 82: 41,94 OK (HHHFFF)
Size 83: 42,95 BAD (HHHFHH)
Size 84: 42,96 OK (HHHFFF)
Size 85: 43,98 BAD (HHHFHH)
Size 86: 43,99 OK (HHHFFF)
Size 87: 44,100 BAD (HHHFHH)
Size 88: 44,101 OK (HHHFFF)
Size 89: 45,102 BAD (HHHFHH)
Size 90: 45,103 OK (HHHFFF)
Size 91: 46,105 BAD (HHHFHH)
Size 92: 46,106 OK (HHHFFF)
Size 93: 47,107 BAD (HHHFHH)
Size 94: 47,108 OK (HHHFFF)
Size 95: 48,109 BAD (HHHFHH)
Size 96: 48,110 OK (HHHFFF)
Size 97: 49,111 BAD (HHHFHH)
Size 98: 49,113 OK (HHHFFF)
Size 99: 50,114 BAD (HHHFHH)
Size 100: 50,115 OK (HHHFFF)
Windows 7
---------
Size 1: 1,2 OK (HHHFFF)
Size 2: 1,2 OK (HHHFFF)
Size 3: 2,3 BAD (FFFFHH)
Size 4: 2,5 OK (HHHFFF)
Size 5: 3,6 BAD (FFFFHH)
Size 6: 3,7 OK (HHHFFF)
Size 7: 4,8 BAD (FFFFHH)
Size 8: 4,9 OK (HHHFFF)
Size 9: 5,10 BAD (FFFFHH)
Size 10: 5,11 OK (HHHFFF)
Size 11: 6,13 BAD (FFFFHH)
Size 12: 6,14 OK (HHHFFF)
Size 13: 7,15 BAD (FFFFHH)
Size 14: 7,16 OK (HHHFFF)
Size 15: 8,17 BAD (FFFFHH)
Size 16: 8,18 OK (HHHFFF)
Size 17: 9,20 BAD (FFFFHH)
Size 18: 9,21 OK (HHHFFF)
Size 19: 10,22 BAD (FFFFHH)
Size 20: 10,23 OK (HHHFFF)
Size 21: 11,24 BAD (FFFFHH)
Size 22: 11,25 OK (HHHFFF)
Size 23: 12,26 BAD (FFFFHH)
Size 24: 12,28 OK (HHHFFF)
Size 25: 13,29 BAD (FFFFHH)
Size 26: 13,30 OK (HHHFFF)
Size 27: 14,31 BAD (FFFFHH)
Size 28: 14,32 OK (HHHFFF)
Size 29: 15,33 BAD (FFFFHH)
Size 30: 15,34 OK (HHHFFF)
Size 31: 16,36 BAD (FFFFHH)
Size 32: 16,37 OK (HHHFFF)
Size 33: 17,38 BAD (FFFFHH)
Size 34: 17,39 OK (HHHFFF)
Size 35: 18,40 BAD (FFFFHH)
Size 36: 18,41 OK (HHHFFF)
Size 37: 19,42 BAD (FFFFHH)
Size 38: 19,44 OK (HHHFFF)
Size 39: 20,45 BAD (FFFFHH)
Size 40: 20,46 OK (HHHFFF)
Size 41: 21,47 BAD (FFFFHH)
Size 42: 21,48 OK (HHHFFF)
Size 43: 22,49 BAD (FFFFHH)
Size 44: 22,51 OK (HHHFFF)
Size 45: 23,52 BAD (FFFFHH)
Size 46: 23,53 OK (HHHFFF)
Size 47: 24,54 BAD (FFFFHH)
Size 48: 24,55 OK (HHHFFF)
Size 49: 25,56 BAD (FFFFHH)
Size 50: 25,57 OK (HHHFFF)
Size 51: 26,59 BAD (FFFFHH)
Size 52: 26,60 OK (HHHFFF)
Size 53: 27,61 BAD (FFFFHH)
Size 54: 27,62 OK (HHHFFF)
Size 55: 28,63 BAD (FFFFHH)
Size 56: 28,64 OK (HHHFFF)
Size 57: 29,65 BAD (FFFFHH)
Size 58: 29,67 OK (HHHFFF)
Size 59: 30,68 BAD (FFFFHH)
Size 60: 30,69 OK (HHHFFF)
Size 61: 31,70 BAD (FFFFHH)
Size 62: 31,71 OK (HHHFFF)
Size 63: 32,72 BAD (FFFFHH)
Size 64: 32,74 OK (HHHFFF)
Size 65: 33,75 BAD (FFFFHH)
Size 66: 33,76 OK (HHHFFF)
Size 67: 34,77 BAD (FFFFHH)
Size 68: 34,78 OK (HHHFFF)
Size 69: 35,79 BAD (FFFFHH)
Size 70: 35,80 OK (HHHFFF)
Size 71: 36,82 BAD (FFFFHH)
Size 72: 36,83 OK (HHHFFF)
Size 73: 37,84 BAD (FFFFHH)
Size 74: 37,85 OK (HHHFFF)
Size 75: 38,86 BAD (FFFFHH)
Size 76: 38,87 OK (HHHFFF)
Size 77: 39,88 BAD (FFFFHH)
Size 78: 39,90 OK (HHHFFF)
Size 79: 40,91 BAD (FFFFHH)
Size 80: 40,92 OK (HHHFFF)
Size 81: 41,93 BAD (FFFFHH)
Size 82: 41,94 OK (HHHFFF)
Size 83: 42,95 BAD (FFFFHH)
Size 84: 42,96 OK (HHHFFF)
Size 85: 43,98 BAD (FFFFHH)
Size 86: 43,99 OK (HHHFFF)
Size 87: 44,100 BAD (FFFFHH)
Size 88: 44,101 OK (HHHFFF)
Size 89: 45,102 BAD (FFFFHH)
Size 90: 45,103 OK (HHHFFF)
Size 91: 46,105 BAD (FFFFHH)
Size 92: 46,106 OK (HHHFFF)
Size 93: 47,107 BAD (FFFFHH)
Size 94: 47,108 OK (HHHFFF)
Size 95: 48,109 BAD (FFFFHH)
Size 96: 48,110 OK (HHHFFF)
Size 97: 49,111 BAD (FFFFHH)
Size 98: 49,113 OK (HHHFFF)
Size 99: 50,114 BAD (FFFFHH)
Size 100: 50,115 OK (HHHFFF)
Windows 8
---------
Size 1: 1,2 OK (HHHFFF)
Size 2: 1,2 OK (HHHFFF)
Size 3: 2,3 BAD (FFFFHH)
Size 4: 2,5 OK (HHHFFF)
Size 5: 3,6 BAD (FFFFHH)
Size 6: 3,7 OK (HHHFFF)
Size 7: 4,8 BAD (FFFFHH)
Size 8: 4,9 OK (HHHFFF)
Size 9: 5,10 BAD (FFFFHH)
Size 10: 5,11 OK (HHHFFF)
Size 11: 6,13 BAD (FFFFHH)
Size 12: 6,14 OK (HHHFFF)
Size 13: 7,15 BAD (FFFFHH)
Size 14: 7,16 OK (HHHFFF)
Size 15: 8,17 BAD (FFFFHH)
Size 16: 8,18 OK (HHHFFF)
Size 17: 9,20 BAD (FFFFHH)
Size 18: 9,21 OK (HHHFFF)
Size 19: 10,22 BAD (FFFFHH)
Size 20: 10,23 OK (HHHFFF)
Size 21: 11,24 BAD (FFFFHH)
Size 22: 11,25 OK (HHHFFF)
Size 23: 12,26 BAD (FFFFHH)
Size 24: 12,28 OK (HHHFFF)
Size 25: 13,29 BAD (FFFFHH)
Size 26: 13,30 OK (HHHFFF)
Size 27: 14,31 BAD (FFFFHH)
Size 28: 14,32 OK (HHHFFF)
Size 29: 15,33 BAD (FFFFHH)
Size 30: 15,34 OK (HHHFFF)
Size 31: 16,36 BAD (FFFFHH)
Size 32: 16,37 OK (HHHFFF)
Size 33: 17,38 BAD (FFFFHH)
Size 34: 17,39 OK (HHHFFF)
Size 35: 18,40 BAD (FFFFHH)
Size 36: 18,41 OK (HHHFFF)
Size 37: 19,42 BAD (FFFFHH)
Size 38: 19,44 OK (HHHFFF)
Size 39: 20,45 BAD (FFFFHH)
Size 40: 20,46 OK (HHHFFF)
Size 41: 21,47 BAD (FFFFHH)
Size 42: 21,48 OK (HHHFFF)
Size 43: 22,49 BAD (FFFFHH)
Size 44: 22,51 OK (HHHFFF)
Size 45: 23,52 BAD (FFFFHH)
Size 46: 23,53 OK (HHHFFF)
Size 47: 24,54 BAD (FFFFHH)
Size 48: 24,55 OK (HHHFFF)
Size 49: 25,56 BAD (FFFFHH)
Size 50: 25,57 OK (HHHFFF)
Size 51: 26,59 BAD (FFFFHH)
Size 52: 26,60 OK (HHHFFF)
Size 53: 27,61 BAD (FFFFHH)
Size 54: 27,62 OK (HHHFFF)
Size 55: 28,63 BAD (FFFFHH)
Size 56: 28,64 OK (HHHFFF)
Size 57: 29,65 BAD (FFFFHH)
Size 58: 29,67 OK (HHHFFF)
Size 59: 30,68 BAD (FFFFHH)
Size 60: 30,69 OK (HHHFFF)
Size 61: 31,70 BAD (FFFFHH)
Size 62: 31,71 OK (HHHFFF)
Size 63: 32,72 BAD (FFFFHH)
Size 64: 32,74 OK (HHHFFF)
Size 65: 33,75 BAD (FFFFHH)
Size 66: 33,76 OK (HHHFFF)
Size 67: 34,77 BAD (FFFFHH)
Size 68: 34,78 OK (HHHFFF)
Size 69: 35,79 BAD (FFFFHH)
Size 70: 35,80 OK (HHHFFF)
Size 71: 36,82 BAD (FFFFHH)
Size 72: 36,83 OK (HHHFFF)
Size 73: 37,84 BAD (FFFFHH)
Size 74: 37,85 OK (HHHFFF)
Size 75: 38,86 BAD (FFFFHH)
Size 76: 38,87 OK (HHHFFF)
Size 77: 39,88 BAD (FFFFHH)
Size 78: 39,90 OK (HHHFFF)
Size 79: 40,91 BAD (FFFFHH)
Size 80: 40,92 OK (HHHFFF)
Size 81: 41,93 BAD (FFFFHH)
Size 82: 41,94 OK (HHHFFF)
Size 83: 42,95 BAD (FFFFHH)
Size 84: 42,96 OK (HHHFFF)
Size 85: 43,98 BAD (FFFFHH)
Size 86: 43,99 OK (HHHFFF)
Size 87: 44,100 BAD (FFFFHH)
Size 88: 44,101 OK (HHHFFF)
Size 89: 45,102 BAD (FFFFHH)
Size 90: 45,103 OK (HHHFFF)
Size 91: 46,105 BAD (FFFFHH)
Size 92: 46,106 OK (HHHFFF)
Size 93: 47,107 BAD (FFFFHH)
Size 94: 47,108 OK (HHHFFF)
Size 95: 48,109 BAD (FFFFHH)
Size 96: 48,110 OK (HHHFFF)
Size 97: 49,111 BAD (FFFFHH)
Size 98: 49,113 OK (HHHFFF)
Size 99: 50,114 BAD (FFFFHH)
Size 100: 50,115 OK (HHHFFF)
Windows 8.1
-----------
Size 1: 1,2 OK (HHHFFF)
Size 2: 1,2 OK (HHHFFF)
Size 3: 2,3 BAD (FFFFHH)
Size 4: 2,5 OK (HHHFFF)
Size 5: 3,6 BAD (FFFFHH)
Size 6: 3,7 OK (HHHFFF)
Size 7: 4,8 BAD (FFFFHH)
Size 8: 4,9 OK (HHHFFF)
Size 9: 5,10 BAD (FFFFHH)
Size 10: 5,11 OK (HHHFFF)
Size 11: 6,13 BAD (FFFFHH)
Size 12: 6,14 OK (HHHFFF)
Size 13: 7,15 BAD (FFFFHH)
Size 14: 7,16 OK (HHHFFF)
Size 15: 8,17 BAD (FFFFHH)
Size 16: 8,18 OK (HHHFFF)
Size 17: 9,20 BAD (FFFFHH)
Size 18: 9,21 OK (HHHFFF)
Size 19: 10,22 BAD (FFFFHH)
Size 20: 10,23 OK (HHHFFF)
Size 21: 11,24 BAD (FFFFHH)
Size 22: 11,25 OK (HHHFFF)
Size 23: 12,26 BAD (FFFFHH)
Size 24: 12,28 OK (HHHFFF)
Size 25: 13,29 BAD (FFFFHH)
Size 26: 13,30 OK (HHHFFF)
Size 27: 14,31 BAD (FFFFHH)
Size 28: 14,32 OK (HHHFFF)
Size 29: 15,33 BAD (FFFFHH)
Size 30: 15,34 OK (HHHFFF)
Size 31: 16,36 BAD (FFFFHH)
Size 32: 16,37 OK (HHHFFF)
Size 33: 17,38 BAD (FFFFHH)
Size 34: 17,39 OK (HHHFFF)
Size 35: 18,40 BAD (FFFFHH)
Size 36: 18,41 OK (HHHFFF)
Size 37: 19,42 BAD (FFFFHH)
Size 38: 19,44 OK (HHHFFF)
Size 39: 20,45 BAD (FFFFHH)
Size 40: 20,46 OK (HHHFFF)
Size 41: 21,47 BAD (FFFFHH)
Size 42: 21,48 OK (HHHFFF)
Size 43: 22,49 BAD (FFFFHH)
Size 44: 22,51 OK (HHHFFF)
Size 45: 23,52 BAD (FFFFHH)
Size 46: 23,53 OK (HHHFFF)
Size 47: 24,54 BAD (FFFFHH)
Size 48: 24,55 OK (HHHFFF)
Size 49: 25,56 BAD (FFFFHH)
Size 50: 25,57 OK (HHHFFF)
Size 51: 26,59 BAD (FFFFHH)
Size 52: 26,60 OK (HHHFFF)
Size 53: 27,61 BAD (FFFFHH)
Size 54: 27,62 OK (HHHFFF)
Size 55: 28,63 BAD (FFFFHH)
Size 56: 28,64 OK (HHHFFF)
Size 57: 29,65 BAD (FFFFHH)
Size 58: 29,67 OK (HHHFFF)
Size 59: 30,68 BAD (FFFFHH)
Size 60: 30,69 OK (HHHFFF)
Size 61: 31,70 BAD (FFFFHH)
Size 62: 31,71 OK (HHHFFF)
Size 63: 32,72 BAD (FFFFHH)
Size 64: 32,74 OK (HHHFFF)
Size 65: 33,75 BAD (FFFFHH)
Size 66: 33,76 OK (HHHFFF)
Size 67: 34,77 BAD (FFFFHH)
Size 68: 34,78 OK (HHHFFF)
Size 69: 35,79 BAD (FFFFHH)
Size 70: 35,80 OK (HHHFFF)
Size 71: 36,82 BAD (FFFFHH)
Size 72: 36,83 OK (HHHFFF)
Size 73: 37,84 BAD (FFFFHH)
Size 74: 37,85 OK (HHHFFF)
Size 75: 38,86 BAD (FFFFHH)
Size 76: 38,87 OK (HHHFFF)
Size 77: 39,88 BAD (FFFFHH)
Size 78: 39,90 OK (HHHFFF)
Size 79: 40,91 BAD (FFFFHH)
Size 80: 40,92 OK (HHHFFF)
Size 81: 41,93 BAD (FFFFHH)
Size 82: 41,94 OK (HHHFFF)
Size 83: 42,95 BAD (FFFFHH)
Size 84: 42,96 OK (HHHFFF)
Size 85: 43,98 BAD (FFFFHH)
Size 86: 43,99 OK (HHHFFF)
Size 87: 44,100 BAD (FFFFHH)
Size 88: 44,101 OK (HHHFFF)
Size 89: 45,102 BAD (FFFFHH)
Size 90: 45,103 OK (HHHFFF)
Size 91: 46,105 BAD (FFFFHH)
Size 92: 46,106 OK (HHHFFF)
Size 93: 47,107 BAD (FFFFHH)
Size 94: 47,108 OK (HHHFFF)
Size 95: 48,109 BAD (FFFFHH)
Size 96: 48,110 OK (HHHFFF)
Size 97: 49,111 BAD (FFFFHH)
Size 98: 49,113 OK (HHHFFF)
Size 99: 50,114 BAD (FFFFHH)
Size 100: 50,115 OK (HHHFFF)
Windows 10 14342 Old Console
----------------------------
Size 1: 1,2 OK (HHHFFF)
Size 2: 1,2 OK (HHHFFF)
Size 3: 2,3 BAD (FFFFHH)
Size 4: 2,5 OK (HHHFFF)
Size 5: 3,6 BAD (FFFFHH)
Size 6: 3,7 OK (HHHFFF)
Size 7: 4,8 BAD (FFFFHH)
Size 8: 4,9 OK (HHHFFF)
Size 9: 5,10 BAD (FFFFHH)
Size 10: 5,11 OK (HHHFFF)
Size 11: 6,13 BAD (FFFFHH)
Size 12: 6,14 OK (HHHFFF)
Size 13: 7,15 BAD (FFFFHH)
Size 14: 7,16 OK (HHHFFF)
Size 15: 8,17 BAD (FFFFHH)
Size 16: 8,18 OK (HHHFFF)
Size 17: 9,20 BAD (FFFFHH)
Size 18: 9,21 OK (HHHFFF)
Size 19: 10,22 BAD (FFFFHH)
Size 20: 10,23 OK (HHHFFF)
Size 21: 11,24 BAD (FFFFHH)
Size 22: 11,25 OK (HHHFFF)
Size 23: 12,26 BAD (FFFFHH)
Size 24: 12,28 OK (HHHFFF)
Size 25: 13,29 BAD (FFFFHH)
Size 26: 13,30 OK (HHHFFF)
Size 27: 14,31 BAD (FFFFHH)
Size 28: 14,32 OK (HHHFFF)
Size 29: 15,33 BAD (FFFFHH)
Size 30: 15,34 OK (HHHFFF)
Size 31: 16,36 BAD (FFFFHH)
Size 32: 16,37 OK (HHHFFF)
Size 33: 17,38 BAD (FFFFHH)
Size 34: 17,39 OK (HHHFFF)
Size 35: 18,40 BAD (FFFFHH)
Size 36: 18,41 OK (HHHFFF)
Size 37: 19,42 BAD (FFFFHH)
Size 38: 19,44 OK (HHHFFF)
Size 39: 20,45 BAD (FFFFHH)
Size 40: 20,46 OK (HHHFFF)
Size 41: 21,47 BAD (FFFFHH)
Size 42: 21,48 OK (HHHFFF)
Size 43: 22,49 BAD (FFFFHH)
Size 44: 22,51 OK (HHHFFF)
Size 45: 23,52 BAD (FFFFHH)
Size 46: 23,53 OK (HHHFFF)
Size 47: 24,54 BAD (FFFFHH)
Size 48: 24,55 OK (HHHFFF)
Size 49: 25,56 BAD (FFFFHH)
Size 50: 25,57 OK (HHHFFF)
Size 51: 26,59 BAD (FFFFHH)
Size 52: 26,60 OK (HHHFFF)
Size 53: 27,61 BAD (FFFFHH)
Size 54: 27,62 OK (HHHFFF)
Size 55: 28,63 BAD (FFFFHH)
Size 56: 28,64 OK (HHHFFF)
Size 57: 29,65 BAD (FFFFHH)
Size 58: 29,67 OK (HHHFFF)
Size 59: 30,68 BAD (FFFFHH)
Size 60: 30,69 OK (HHHFFF)
Size 61: 31,70 BAD (FFFFHH)
Size 62: 31,71 OK (HHHFFF)
Size 63: 32,72 BAD (FFFFHH)
Size 64: 32,74 OK (HHHFFF)
Size 65: 33,75 BAD (FFFFHH)
Size 66: 33,76 OK (HHHFFF)
Size 67: 34,77 BAD (FFFFHH)
Size 68: 34,78 OK (HHHFFF)
Size 69: 35,79 BAD (FFFFHH)
Size 70: 35,80 OK (HHHFFF)
Size 71: 36,82 BAD (FFFFHH)
Size 72: 36,83 OK (HHHFFF)
Size 73: 37,84 BAD (FFFFHH)
Size 74: 37,85 OK (HHHFFF)
Size 75: 38,86 BAD (FFFFHH)
Size 76: 38,87 OK (HHHFFF)
Size 77: 39,88 BAD (FFFFHH)
Size 78: 39,90 OK (HHHFFF)
Size 79: 40,91 BAD (FFFFHH)
Size 80: 40,92 OK (HHHFFF)
Size 81: 41,93 BAD (FFFFHH)
Size 82: 41,94 OK (HHHFFF)
Size 83: 42,95 BAD (FFFFHH)
Size 84: 42,96 OK (HHHFFF)
Size 85: 43,98 BAD (FFFFHH)
Size 86: 43,99 OK (HHHFFF)
Size 87: 44,100 BAD (FFFFHH)
Size 88: 44,101 OK (HHHFFF)
Size 89: 45,102 BAD (FFFFHH)
Size 90: 45,103 OK (HHHFFF)
Size 91: 46,105 BAD (FFFFHH)
Size 92: 46,106 OK (HHHFFF)
Size 93: 47,107 BAD (FFFFHH)
Size 94: 47,108 OK (HHHFFF)
Size 95: 48,109 BAD (FFFFHH)
Size 96: 48,110 OK (HHHFFF)
Size 97: 49,111 BAD (FFFFHH)
Size 98: 49,113 OK (HHHFFF)
Size 99: 50,114 BAD (FFFFHH)
Size 100: 50,115 OK (HHHFFF)
Windows 10 14342 New Console
----------------------------
Size 1: 1,1 OK (HHHFFF)
Size 2: 1,2 OK (HHHFFF)
Size 3: 2,3 OK (HHHFFF)
Size 4: 2,4 OK (HHHFFF)
Size 5: 3,5 OK (HHHFFF)
Size 6: 3,6 OK (HHHFFF)
Size 7: 4,7 OK (HHHFFF)
Size 8: 4,8 OK (HHHFFF)
Size 9: 5,9 OK (HHHFFF)
Size 10: 5,10 OK (HHHFFF)
Size 11: 6,11 OK (HHHFFF)
Size 12: 6,12 OK (HHHFFF)
Size 13: 7,13 OK (HHHFFF)
Size 14: 7,14 OK (HHHFFF)
Size 15: 8,15 OK (HHHFFF)
Size 16: 8,16 OK (HHHFFF)
Size 17: 9,17 OK (HHHFFF)
Size 18: 9,18 OK (HHHFFF)
Size 19: 10,19 OK (HHHFFF)
Size 20: 10,20 OK (HHHFFF)
Size 21: 11,21 OK (HHHFFF)
Size 22: 11,22 OK (HHHFFF)
Size 23: 12,23 OK (HHHFFF)
Size 24: 12,24 OK (HHHFFF)
Size 25: 13,25 OK (HHHFFF)
Size 26: 13,26 OK (HHHFFF)
Size 27: 14,27 OK (HHHFFF)
Size 28: 14,28 OK (HHHFFF)
Size 29: 15,29 OK (HHHFFF)
Size 30: 15,30 OK (HHHFFF)
Size 31: 16,31 OK (HHHFFF)
Size 32: 16,32 OK (HHHFFF)
Size 33: 17,33 OK (HHHFFF)
Size 34: 17,34 OK (HHHFFF)
Size 35: 18,35 OK (HHHFFF)
Size 36: 18,36 OK (HHHFFF)
Size 37: 19,37 OK (HHHFFF)
Size 38: 19,38 OK (HHHFFF)
Size 39: 20,39 OK (HHHFFF)
Size 40: 20,40 OK (HHHFFF)
Size 41: 21,41 OK (HHHFFF)
Size 42: 21,42 OK (HHHFFF)
Size 43: 22,43 OK (HHHFFF)
Size 44: 22,44 OK (HHHFFF)
Size 45: 23,45 OK (HHHFFF)
Size 46: 23,46 OK (HHHFFF)
Size 47: 24,47 OK (HHHFFF)
Size 48: 24,48 OK (HHHFFF)
Size 49: 25,49 OK (HHHFFF)
Size 50: 25,50 OK (HHHFFF)
Size 51: 26,51 OK (HHHFFF)
Size 52: 26,52 OK (HHHFFF)
Size 53: 27,53 OK (HHHFFF)
Size 54: 27,54 OK (HHHFFF)
Size 55: 28,55 OK (HHHFFF)
Size 56: 28,56 OK (HHHFFF)
Size 57: 29,57 OK (HHHFFF)
Size 58: 29,58 OK (HHHFFF)
Size 59: 30,59 OK (HHHFFF)
Size 60: 30,60 OK (HHHFFF)
Size 61: 31,61 OK (HHHFFF)
Size 62: 31,62 OK (HHHFFF)
Size 63: 32,63 OK (HHHFFF)
Size 64: 32,64 OK (HHHFFF)
Size 65: 33,65 OK (HHHFFF)
Size 66: 33,66 OK (HHHFFF)
Size 67: 34,67 OK (HHHFFF)
Size 68: 34,68 OK (HHHFFF)
Size 69: 35,69 OK (HHHFFF)
Size 70: 35,70 OK (HHHFFF)
Size 71: 36,71 OK (HHHFFF)
Size 72: 36,72 OK (HHHFFF)
Size 73: 37,73 OK (HHHFFF)
Size 74: 37,74 OK (HHHFFF)
Size 75: 38,75 OK (HHHFFF)
Size 76: 38,76 OK (HHHFFF)
Size 77: 39,77 OK (HHHFFF)
Size 78: 39,78 OK (HHHFFF)
Size 79: 40,79 OK (HHHFFF)
Size 80: 40,80 OK (HHHFFF)
Size 81: 41,81 OK (HHHFFF)
Size 82: 41,82 OK (HHHFFF)
Size 83: 42,83 OK (HHHFFF)
Size 84: 42,84 OK (HHHFFF)
Size 85: 43,85 OK (HHHFFF)
Size 86: 43,86 OK (HHHFFF)
Size 87: 44,87 OK (HHHFFF)
Size 88: 44,88 OK (HHHFFF)
Size 89: 45,89 OK (HHHFFF)
Size 90: 45,90 OK (HHHFFF)
Size 91: 46,91 OK (HHHFFF)
Size 92: 46,92 OK (HHHFFF)
Size 93: 47,93 OK (HHHFFF)
Size 94: 47,94 OK (HHHFFF)
Size 95: 48,95 OK (HHHFFF)
Size 96: 48,96 OK (HHHFFF)
Size 97: 49,97 OK (HHHFFF)
Size 98: 49,98 OK (HHHFFF)
Size 99: 50,99 OK (HHHFFF)
Size 100: 50,100 OK (HHHFFF)

View File

@@ -0,0 +1,630 @@
===========================================================
Code Page 950, Chinese Traditional (Taiwan), MingLight font
===========================================================
Options: -face-minglight -family 0x36
Chars: A2 A3 2014 3044 30FC 4000
Vista
-----
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,4 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (HHHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (HHHFHH)
Size 8: 4,10 GOOD (HHFFFF)
Size 9: 5,11 BAD (HHHFHH)
Size 10: 5,12 GOOD (HHFFFF)
Size 11: 6,13 BAD (HHHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,16 BAD (HHHFHH)
Size 14: 7,17 GOOD (HHFFFF)
Size 15: 8,18 BAD (HHHFHH)
Size 16: 8,19 GOOD (HHFFFF)
Size 17: 9,20 BAD (HHHFHH)
Size 18: 9,22 GOOD (HHFFFF)
Size 19: 10,23 BAD (HHHFHH)
Size 20: 10,24 GOOD (HHFFFF)
Size 21: 11,25 BAD (HHHFHH)
Size 22: 11,26 GOOD (HHFFFF)
Size 23: 12,28 BAD (HHHFHH)
Size 24: 12,29 GOOD (HHFFFF)
Size 25: 13,30 BAD (HHHFHH)
Size 26: 13,31 GOOD (HHFFFF)
Size 27: 14,32 BAD (HHHFHH)
Size 28: 14,34 GOOD (HHFFFF)
Size 29: 15,35 BAD (HHHFHH)
Size 30: 15,36 GOOD (HHFFFF)
Size 31: 16,37 BAD (HHHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,40 BAD (HHHFHH)
Size 34: 17,41 GOOD (HHFFFF)
Size 35: 18,42 BAD (HHHFHH)
Size 36: 18,43 GOOD (HHFFFF)
Size 37: 19,44 BAD (HHHFHH)
Size 38: 19,46 GOOD (HHFFFF)
Size 39: 20,47 BAD (HHHFHH)
Size 40: 20,48 GOOD (HHFFFF)
Size 41: 21,49 BAD (HHHFHH)
Size 42: 21,50 GOOD (HHFFFF)
Size 43: 22,52 BAD (HHHFHH)
Size 44: 22,53 GOOD (HHFFFF)
Size 45: 23,54 BAD (HHHFHH)
Size 46: 23,55 GOOD (HHFFFF)
Size 47: 24,56 BAD (HHHFHH)
Size 48: 24,58 GOOD (HHFFFF)
Size 49: 25,59 BAD (HHHFHH)
Size 50: 25,60 GOOD (HHFFFF)
Size 51: 26,61 BAD (HHHFHH)
Size 52: 26,62 GOOD (HHFFFF)
Size 53: 27,64 BAD (HHHFHH)
Size 54: 27,65 GOOD (HHFFFF)
Size 55: 28,66 BAD (HHHFHH)
Size 56: 28,67 GOOD (HHFFFF)
Size 57: 29,68 BAD (HHHFHH)
Size 58: 29,70 GOOD (HHFFFF)
Size 59: 30,71 BAD (HHHFHH)
Size 60: 30,72 GOOD (HHFFFF)
Size 61: 31,73 BAD (HHHFHH)
Size 62: 31,74 GOOD (HHFFFF)
Size 63: 32,76 BAD (HHHFHH)
Size 64: 32,77 GOOD (HHFFFF)
Size 65: 33,78 BAD (HHHFHH)
Size 66: 33,79 GOOD (HHFFFF)
Size 67: 34,80 BAD (HHHFHH)
Size 68: 34,82 GOOD (HHFFFF)
Size 69: 35,83 BAD (HHHFHH)
Size 70: 35,84 GOOD (HHFFFF)
Size 71: 36,85 BAD (HHHFHH)
Size 72: 36,86 GOOD (HHFFFF)
Size 73: 37,88 BAD (HHHFHH)
Size 74: 37,89 GOOD (HHFFFF)
Size 75: 38,90 BAD (HHHFHH)
Size 76: 38,91 GOOD (HHFFFF)
Size 77: 39,92 BAD (HHHFHH)
Size 78: 39,94 GOOD (HHFFFF)
Size 79: 40,95 BAD (HHHFHH)
Size 80: 40,96 GOOD (HHFFFF)
Size 81: 41,97 BAD (HHHFHH)
Size 82: 41,98 GOOD (HHFFFF)
Size 83: 42,100 BAD (HHHFHH)
Size 84: 42,101 GOOD (HHFFFF)
Size 85: 43,102 BAD (HHHFHH)
Size 86: 43,103 GOOD (HHFFFF)
Size 87: 44,104 BAD (HHHFHH)
Size 88: 44,106 GOOD (HHFFFF)
Size 89: 45,107 BAD (HHHFHH)
Size 90: 45,108 GOOD (HHFFFF)
Size 91: 46,109 BAD (HHHFHH)
Size 92: 46,110 GOOD (HHFFFF)
Size 93: 47,112 BAD (HHHFHH)
Size 94: 47,113 GOOD (HHFFFF)
Size 95: 48,114 BAD (HHHFHH)
Size 96: 48,115 GOOD (HHFFFF)
Size 97: 49,116 BAD (HHHFHH)
Size 98: 49,118 GOOD (HHFFFF)
Size 99: 50,119 BAD (HHHFHH)
Size 100: 50,120 GOOD (HHFFFF)
Windows 7
---------
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,4 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (FFHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (FFHFHH)
Size 8: 4,10 GOOD (HHFFFF)
Size 9: 5,11 BAD (FFHFHH)
Size 10: 5,12 GOOD (HHFFFF)
Size 11: 6,13 BAD (FFHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,16 BAD (FFHFHH)
Size 14: 7,17 GOOD (HHFFFF)
Size 15: 8,18 BAD (FFHFHH)
Size 16: 8,19 GOOD (HHFFFF)
Size 17: 9,20 BAD (FFHFHH)
Size 18: 9,22 GOOD (HHFFFF)
Size 19: 10,23 BAD (FFHFHH)
Size 20: 10,24 GOOD (HHFFFF)
Size 21: 11,25 BAD (FFHFHH)
Size 22: 11,26 GOOD (HHFFFF)
Size 23: 12,28 BAD (FFHFHH)
Size 24: 12,29 GOOD (HHFFFF)
Size 25: 13,30 BAD (FFHFHH)
Size 26: 13,31 GOOD (HHFFFF)
Size 27: 14,32 BAD (FFHFHH)
Size 28: 14,34 GOOD (HHFFFF)
Size 29: 15,35 BAD (FFHFHH)
Size 30: 15,36 GOOD (HHFFFF)
Size 31: 16,37 BAD (FFHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,40 BAD (FFHFHH)
Size 34: 17,41 GOOD (HHFFFF)
Size 35: 18,42 BAD (FFHFHH)
Size 36: 18,43 GOOD (HHFFFF)
Size 37: 19,44 BAD (FFHFHH)
Size 38: 19,46 GOOD (HHFFFF)
Size 39: 20,47 BAD (FFHFHH)
Size 40: 20,48 GOOD (HHFFFF)
Size 41: 21,49 BAD (FFHFHH)
Size 42: 21,50 GOOD (HHFFFF)
Size 43: 22,52 BAD (FFHFHH)
Size 44: 22,53 GOOD (HHFFFF)
Size 45: 23,54 BAD (FFHFHH)
Size 46: 23,55 GOOD (HHFFFF)
Size 47: 24,56 BAD (FFHFHH)
Size 48: 24,58 GOOD (HHFFFF)
Size 49: 25,59 BAD (FFHFHH)
Size 50: 25,60 GOOD (HHFFFF)
Size 51: 26,61 BAD (FFHFHH)
Size 52: 26,62 GOOD (HHFFFF)
Size 53: 27,64 BAD (FFHFHH)
Size 54: 27,65 GOOD (HHFFFF)
Size 55: 28,66 BAD (FFHFHH)
Size 56: 28,67 GOOD (HHFFFF)
Size 57: 29,68 BAD (FFHFHH)
Size 58: 29,70 GOOD (HHFFFF)
Size 59: 30,71 BAD (FFHFHH)
Size 60: 30,72 GOOD (HHFFFF)
Size 61: 31,73 BAD (FFHFHH)
Size 62: 31,74 GOOD (HHFFFF)
Size 63: 32,76 BAD (FFHFHH)
Size 64: 32,77 GOOD (HHFFFF)
Size 65: 33,78 BAD (FFHFHH)
Size 66: 33,79 GOOD (HHFFFF)
Size 67: 34,80 BAD (FFHFHH)
Size 68: 34,82 GOOD (HHFFFF)
Size 69: 35,83 BAD (FFHFHH)
Size 70: 35,84 GOOD (HHFFFF)
Size 71: 36,85 BAD (FFHFHH)
Size 72: 36,86 GOOD (HHFFFF)
Size 73: 37,88 BAD (FFHFHH)
Size 74: 37,89 GOOD (HHFFFF)
Size 75: 38,90 BAD (FFHFHH)
Size 76: 38,91 GOOD (HHFFFF)
Size 77: 39,92 BAD (FFHFHH)
Size 78: 39,94 GOOD (HHFFFF)
Size 79: 40,95 BAD (FFHFHH)
Size 80: 40,96 GOOD (HHFFFF)
Size 81: 41,97 BAD (FFHFHH)
Size 82: 41,98 GOOD (HHFFFF)
Size 83: 42,100 BAD (FFHFHH)
Size 84: 42,101 GOOD (HHFFFF)
Size 85: 43,102 BAD (FFHFHH)
Size 86: 43,103 GOOD (HHFFFF)
Size 87: 44,104 BAD (FFHFHH)
Size 88: 44,106 GOOD (HHFFFF)
Size 89: 45,107 BAD (FFHFHH)
Size 90: 45,108 GOOD (HHFFFF)
Size 91: 46,109 BAD (FFHFHH)
Size 92: 46,110 GOOD (HHFFFF)
Size 93: 47,112 BAD (FFHFHH)
Size 94: 47,113 GOOD (HHFFFF)
Size 95: 48,114 BAD (FFHFHH)
Size 96: 48,115 GOOD (HHFFFF)
Size 97: 49,116 BAD (FFHFHH)
Size 98: 49,118 GOOD (HHFFFF)
Size 99: 50,119 BAD (FFHFHH)
Size 100: 50,120 GOOD (HHFFFF)
Windows 8
---------
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,4 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (FFHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (FFHFHH)
Size 8: 4,10 GOOD (HHFFFF)
Size 9: 5,11 BAD (FFHFHH)
Size 10: 5,12 GOOD (HHFFFF)
Size 11: 6,13 BAD (FFHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,16 BAD (FFHFHH)
Size 14: 7,17 GOOD (HHFFFF)
Size 15: 8,18 BAD (FFHFHH)
Size 16: 8,19 GOOD (HHFFFF)
Size 17: 9,20 BAD (FFHFHH)
Size 18: 9,22 GOOD (HHFFFF)
Size 19: 10,23 BAD (FFHFHH)
Size 20: 10,24 GOOD (HHFFFF)
Size 21: 11,25 BAD (FFHFHH)
Size 22: 11,26 GOOD (HHFFFF)
Size 23: 12,28 BAD (FFHFHH)
Size 24: 12,29 GOOD (HHFFFF)
Size 25: 13,30 BAD (FFHFHH)
Size 26: 13,31 GOOD (HHFFFF)
Size 27: 14,32 BAD (FFHFHH)
Size 28: 14,34 GOOD (HHFFFF)
Size 29: 15,35 BAD (FFHFHH)
Size 30: 15,36 GOOD (HHFFFF)
Size 31: 16,37 BAD (FFHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,40 BAD (FFHFHH)
Size 34: 17,41 GOOD (HHFFFF)
Size 35: 18,42 BAD (FFHFHH)
Size 36: 18,43 GOOD (HHFFFF)
Size 37: 19,44 BAD (FFHFHH)
Size 38: 19,46 GOOD (HHFFFF)
Size 39: 20,47 BAD (FFHFHH)
Size 40: 20,48 GOOD (HHFFFF)
Size 41: 21,49 BAD (FFHFHH)
Size 42: 21,50 GOOD (HHFFFF)
Size 43: 22,52 BAD (FFHFHH)
Size 44: 22,53 GOOD (HHFFFF)
Size 45: 23,54 BAD (FFHFHH)
Size 46: 23,55 GOOD (HHFFFF)
Size 47: 24,56 BAD (FFHFHH)
Size 48: 24,58 GOOD (HHFFFF)
Size 49: 25,59 BAD (FFHFHH)
Size 50: 25,60 GOOD (HHFFFF)
Size 51: 26,61 BAD (FFHFHH)
Size 52: 26,62 GOOD (HHFFFF)
Size 53: 27,64 BAD (FFHFHH)
Size 54: 27,65 GOOD (HHFFFF)
Size 55: 28,66 BAD (FFHFHH)
Size 56: 28,67 GOOD (HHFFFF)
Size 57: 29,68 BAD (FFHFHH)
Size 58: 29,70 GOOD (HHFFFF)
Size 59: 30,71 BAD (FFHFHH)
Size 60: 30,72 GOOD (HHFFFF)
Size 61: 31,73 BAD (FFHFHH)
Size 62: 31,74 GOOD (HHFFFF)
Size 63: 32,76 BAD (FFHFHH)
Size 64: 32,77 GOOD (HHFFFF)
Size 65: 33,78 BAD (FFHFHH)
Size 66: 33,79 GOOD (HHFFFF)
Size 67: 34,80 BAD (FFHFHH)
Size 68: 34,82 GOOD (HHFFFF)
Size 69: 35,83 BAD (FFHFHH)
Size 70: 35,84 GOOD (HHFFFF)
Size 71: 36,85 BAD (FFHFHH)
Size 72: 36,86 GOOD (HHFFFF)
Size 73: 37,88 BAD (FFHFHH)
Size 74: 37,89 GOOD (HHFFFF)
Size 75: 38,90 BAD (FFHFHH)
Size 76: 38,91 GOOD (HHFFFF)
Size 77: 39,92 BAD (FFHFHH)
Size 78: 39,94 GOOD (HHFFFF)
Size 79: 40,95 BAD (FFHFHH)
Size 80: 40,96 GOOD (HHFFFF)
Size 81: 41,97 BAD (FFHFHH)
Size 82: 41,98 GOOD (HHFFFF)
Size 83: 42,100 BAD (FFHFHH)
Size 84: 42,101 GOOD (HHFFFF)
Size 85: 43,102 BAD (FFHFHH)
Size 86: 43,103 GOOD (HHFFFF)
Size 87: 44,104 BAD (FFHFHH)
Size 88: 44,106 GOOD (HHFFFF)
Size 89: 45,107 BAD (FFHFHH)
Size 90: 45,108 GOOD (HHFFFF)
Size 91: 46,109 BAD (FFHFHH)
Size 92: 46,110 GOOD (HHFFFF)
Size 93: 47,112 BAD (FFHFHH)
Size 94: 47,113 GOOD (HHFFFF)
Size 95: 48,114 BAD (FFHFHH)
Size 96: 48,115 GOOD (HHFFFF)
Size 97: 49,116 BAD (FFHFHH)
Size 98: 49,118 GOOD (HHFFFF)
Size 99: 50,119 BAD (FFHFHH)
Size 100: 50,120 GOOD (HHFFFF)
Windows 8.1
-----------
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,4 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (FFHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (FFHFHH)
Size 8: 4,10 GOOD (HHFFFF)
Size 9: 5,11 BAD (FFHFHH)
Size 10: 5,12 GOOD (HHFFFF)
Size 11: 6,13 BAD (FFHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,16 BAD (FFHFHH)
Size 14: 7,17 GOOD (HHFFFF)
Size 15: 8,18 BAD (FFHFHH)
Size 16: 8,19 GOOD (HHFFFF)
Size 17: 9,20 BAD (FFHFHH)
Size 18: 9,22 GOOD (HHFFFF)
Size 19: 10,23 BAD (FFHFHH)
Size 20: 10,24 GOOD (HHFFFF)
Size 21: 11,25 BAD (FFHFHH)
Size 22: 11,26 GOOD (HHFFFF)
Size 23: 12,28 BAD (FFHFHH)
Size 24: 12,29 GOOD (HHFFFF)
Size 25: 13,30 BAD (FFHFHH)
Size 26: 13,31 GOOD (HHFFFF)
Size 27: 14,32 BAD (FFHFHH)
Size 28: 14,34 GOOD (HHFFFF)
Size 29: 15,35 BAD (FFHFHH)
Size 30: 15,36 GOOD (HHFFFF)
Size 31: 16,37 BAD (FFHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,40 BAD (FFHFHH)
Size 34: 17,41 GOOD (HHFFFF)
Size 35: 18,42 BAD (FFHFHH)
Size 36: 18,43 GOOD (HHFFFF)
Size 37: 19,44 BAD (FFHFHH)
Size 38: 19,46 GOOD (HHFFFF)
Size 39: 20,47 BAD (FFHFHH)
Size 40: 20,48 GOOD (HHFFFF)
Size 41: 21,49 BAD (FFHFHH)
Size 42: 21,50 GOOD (HHFFFF)
Size 43: 22,52 BAD (FFHFHH)
Size 44: 22,53 GOOD (HHFFFF)
Size 45: 23,54 BAD (FFHFHH)
Size 46: 23,55 GOOD (HHFFFF)
Size 47: 24,56 BAD (FFHFHH)
Size 48: 24,58 GOOD (HHFFFF)
Size 49: 25,59 BAD (FFHFHH)
Size 50: 25,60 GOOD (HHFFFF)
Size 51: 26,61 BAD (FFHFHH)
Size 52: 26,62 GOOD (HHFFFF)
Size 53: 27,64 BAD (FFHFHH)
Size 54: 27,65 GOOD (HHFFFF)
Size 55: 28,66 BAD (FFHFHH)
Size 56: 28,67 GOOD (HHFFFF)
Size 57: 29,68 BAD (FFHFHH)
Size 58: 29,70 GOOD (HHFFFF)
Size 59: 30,71 BAD (FFHFHH)
Size 60: 30,72 GOOD (HHFFFF)
Size 61: 31,73 BAD (FFHFHH)
Size 62: 31,74 GOOD (HHFFFF)
Size 63: 32,76 BAD (FFHFHH)
Size 64: 32,77 GOOD (HHFFFF)
Size 65: 33,78 BAD (FFHFHH)
Size 66: 33,79 GOOD (HHFFFF)
Size 67: 34,80 BAD (FFHFHH)
Size 68: 34,82 GOOD (HHFFFF)
Size 69: 35,83 BAD (FFHFHH)
Size 70: 35,84 GOOD (HHFFFF)
Size 71: 36,85 BAD (FFHFHH)
Size 72: 36,86 GOOD (HHFFFF)
Size 73: 37,88 BAD (FFHFHH)
Size 74: 37,89 GOOD (HHFFFF)
Size 75: 38,90 BAD (FFHFHH)
Size 76: 38,91 GOOD (HHFFFF)
Size 77: 39,92 BAD (FFHFHH)
Size 78: 39,94 GOOD (HHFFFF)
Size 79: 40,95 BAD (FFHFHH)
Size 80: 40,96 GOOD (HHFFFF)
Size 81: 41,97 BAD (FFHFHH)
Size 82: 41,98 GOOD (HHFFFF)
Size 83: 42,100 BAD (FFHFHH)
Size 84: 42,101 GOOD (HHFFFF)
Size 85: 43,102 BAD (FFHFHH)
Size 86: 43,103 GOOD (HHFFFF)
Size 87: 44,104 BAD (FFHFHH)
Size 88: 44,106 GOOD (HHFFFF)
Size 89: 45,107 BAD (FFHFHH)
Size 90: 45,108 GOOD (HHFFFF)
Size 91: 46,109 BAD (FFHFHH)
Size 92: 46,110 GOOD (HHFFFF)
Size 93: 47,112 BAD (FFHFHH)
Size 94: 47,113 GOOD (HHFFFF)
Size 95: 48,114 BAD (FFHFHH)
Size 96: 48,115 GOOD (HHFFFF)
Size 97: 49,116 BAD (FFHFHH)
Size 98: 49,118 GOOD (HHFFFF)
Size 99: 50,119 BAD (FFHFHH)
Size 100: 50,120 GOOD (HHFFFF)
Windows 10 14342 Old Console
----------------------------
Size 1: 1,2 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,4 BAD (FFHFHH)
Size 4: 2,5 GOOD (HHFFFF)
Size 5: 3,6 BAD (FFHFHH)
Size 6: 3,7 GOOD (HHFFFF)
Size 7: 4,8 BAD (FFHFHH)
Size 8: 4,10 GOOD (HHFFFF)
Size 9: 5,11 BAD (FFHFHH)
Size 10: 5,12 GOOD (HHFFFF)
Size 11: 6,13 BAD (FFHFHH)
Size 12: 6,14 GOOD (HHFFFF)
Size 13: 7,16 BAD (FFHFHH)
Size 14: 7,17 GOOD (HHFFFF)
Size 15: 8,18 BAD (FFHFHH)
Size 16: 8,19 GOOD (HHFFFF)
Size 17: 9,20 BAD (FFHFHH)
Size 18: 9,22 GOOD (HHFFFF)
Size 19: 10,23 BAD (FFHFHH)
Size 20: 10,24 GOOD (HHFFFF)
Size 21: 11,25 BAD (FFHFHH)
Size 22: 11,26 GOOD (HHFFFF)
Size 23: 12,28 BAD (FFHFHH)
Size 24: 12,29 GOOD (HHFFFF)
Size 25: 13,30 BAD (FFHFHH)
Size 26: 13,31 GOOD (HHFFFF)
Size 27: 14,32 BAD (FFHFHH)
Size 28: 14,34 GOOD (HHFFFF)
Size 29: 15,35 BAD (FFHFHH)
Size 30: 15,36 GOOD (HHFFFF)
Size 31: 16,37 BAD (FFHFHH)
Size 32: 16,38 GOOD (HHFFFF)
Size 33: 17,40 BAD (FFHFHH)
Size 34: 17,41 GOOD (HHFFFF)
Size 35: 18,42 BAD (FFHFHH)
Size 36: 18,43 GOOD (HHFFFF)
Size 37: 19,44 BAD (FFHFHH)
Size 38: 19,46 GOOD (HHFFFF)
Size 39: 20,47 BAD (FFHFHH)
Size 40: 20,48 GOOD (HHFFFF)
Size 41: 21,49 BAD (FFHFHH)
Size 42: 21,50 GOOD (HHFFFF)
Size 43: 22,52 BAD (FFHFHH)
Size 44: 22,53 GOOD (HHFFFF)
Size 45: 23,54 BAD (FFHFHH)
Size 46: 23,55 GOOD (HHFFFF)
Size 47: 24,56 BAD (FFHFHH)
Size 48: 24,58 GOOD (HHFFFF)
Size 49: 25,59 BAD (FFHFHH)
Size 50: 25,60 GOOD (HHFFFF)
Size 51: 26,61 BAD (FFHFHH)
Size 52: 26,62 GOOD (HHFFFF)
Size 53: 27,64 BAD (FFHFHH)
Size 54: 27,65 GOOD (HHFFFF)
Size 55: 28,66 BAD (FFHFHH)
Size 56: 28,67 GOOD (HHFFFF)
Size 57: 29,68 BAD (FFHFHH)
Size 58: 29,70 GOOD (HHFFFF)
Size 59: 30,71 BAD (FFHFHH)
Size 60: 30,72 GOOD (HHFFFF)
Size 61: 31,73 BAD (FFHFHH)
Size 62: 31,74 GOOD (HHFFFF)
Size 63: 32,76 BAD (FFHFHH)
Size 64: 32,77 GOOD (HHFFFF)
Size 65: 33,78 BAD (FFHFHH)
Size 66: 33,79 GOOD (HHFFFF)
Size 67: 34,80 BAD (FFHFHH)
Size 68: 34,82 GOOD (HHFFFF)
Size 69: 35,83 BAD (FFHFHH)
Size 70: 35,84 GOOD (HHFFFF)
Size 71: 36,85 BAD (FFHFHH)
Size 72: 36,86 GOOD (HHFFFF)
Size 73: 37,88 BAD (FFHFHH)
Size 74: 37,89 GOOD (HHFFFF)
Size 75: 38,90 BAD (FFHFHH)
Size 76: 38,91 GOOD (HHFFFF)
Size 77: 39,92 BAD (FFHFHH)
Size 78: 39,94 GOOD (HHFFFF)
Size 79: 40,95 BAD (FFHFHH)
Size 80: 40,96 GOOD (HHFFFF)
Size 81: 41,97 BAD (FFHFHH)
Size 82: 41,98 GOOD (HHFFFF)
Size 83: 42,100 BAD (FFHFHH)
Size 84: 42,101 GOOD (HHFFFF)
Size 85: 43,102 BAD (FFHFHH)
Size 86: 43,103 GOOD (HHFFFF)
Size 87: 44,104 BAD (FFHFHH)
Size 88: 44,106 GOOD (HHFFFF)
Size 89: 45,107 BAD (FFHFHH)
Size 90: 45,108 GOOD (HHFFFF)
Size 91: 46,109 BAD (FFHFHH)
Size 92: 46,110 GOOD (HHFFFF)
Size 93: 47,112 BAD (FFHFHH)
Size 94: 47,113 GOOD (HHFFFF)
Size 95: 48,114 BAD (FFHFHH)
Size 96: 48,115 GOOD (HHFFFF)
Size 97: 49,116 BAD (FFHFHH)
Size 98: 49,118 GOOD (HHFFFF)
Size 99: 50,119 BAD (FFHFHH)
Size 100: 50,120 GOOD (HHFFFF)
Windows 10 14342 New Console
----------------------------
Size 1: 1,1 GOOD (HHFFFF)
Size 2: 1,2 GOOD (HHFFFF)
Size 3: 2,3 GOOD (HHFFFF)
Size 4: 2,4 GOOD (HHFFFF)
Size 5: 3,5 GOOD (HHFFFF)
Size 6: 3,6 GOOD (HHFFFF)
Size 7: 4,7 GOOD (HHFFFF)
Size 8: 4,8 GOOD (HHFFFF)
Size 9: 5,9 GOOD (HHFFFF)
Size 10: 5,10 GOOD (HHFFFF)
Size 11: 6,11 GOOD (HHFFFF)
Size 12: 6,12 GOOD (HHFFFF)
Size 13: 7,13 GOOD (HHFFFF)
Size 14: 7,14 GOOD (HHFFFF)
Size 15: 8,15 GOOD (HHFFFF)
Size 16: 8,16 GOOD (HHFFFF)
Size 17: 9,17 GOOD (HHFFFF)
Size 18: 9,18 GOOD (HHFFFF)
Size 19: 10,19 GOOD (HHFFFF)
Size 20: 10,20 GOOD (HHFFFF)
Size 21: 11,21 GOOD (HHFFFF)
Size 22: 11,22 GOOD (HHFFFF)
Size 23: 12,23 GOOD (HHFFFF)
Size 24: 12,24 GOOD (HHFFFF)
Size 25: 13,25 GOOD (HHFFFF)
Size 26: 13,26 GOOD (HHFFFF)
Size 27: 14,27 GOOD (HHFFFF)
Size 28: 14,28 GOOD (HHFFFF)
Size 29: 15,29 GOOD (HHFFFF)
Size 30: 15,30 GOOD (HHFFFF)
Size 31: 16,31 GOOD (HHFFFF)
Size 32: 16,32 GOOD (HHFFFF)
Size 33: 17,33 GOOD (HHFFFF)
Size 34: 17,34 GOOD (HHFFFF)
Size 35: 18,35 GOOD (HHFFFF)
Size 36: 18,36 GOOD (HHFFFF)
Size 37: 19,37 GOOD (HHFFFF)
Size 38: 19,38 GOOD (HHFFFF)
Size 39: 20,39 GOOD (HHFFFF)
Size 40: 20,40 GOOD (HHFFFF)
Size 41: 21,41 GOOD (HHFFFF)
Size 42: 21,42 GOOD (HHFFFF)
Size 43: 22,43 GOOD (HHFFFF)
Size 44: 22,44 GOOD (HHFFFF)
Size 45: 23,45 GOOD (HHFFFF)
Size 46: 23,46 GOOD (HHFFFF)
Size 47: 24,47 GOOD (HHFFFF)
Size 48: 24,48 GOOD (HHFFFF)
Size 49: 25,49 GOOD (HHFFFF)
Size 50: 25,50 GOOD (HHFFFF)
Size 51: 26,51 GOOD (HHFFFF)
Size 52: 26,52 GOOD (HHFFFF)
Size 53: 27,53 GOOD (HHFFFF)
Size 54: 27,54 GOOD (HHFFFF)
Size 55: 28,55 GOOD (HHFFFF)
Size 56: 28,56 GOOD (HHFFFF)
Size 57: 29,57 GOOD (HHFFFF)
Size 58: 29,58 GOOD (HHFFFF)
Size 59: 30,59 GOOD (HHFFFF)
Size 60: 30,60 GOOD (HHFFFF)
Size 61: 31,61 GOOD (HHFFFF)
Size 62: 31,62 GOOD (HHFFFF)
Size 63: 32,63 GOOD (HHFFFF)
Size 64: 32,64 GOOD (HHFFFF)
Size 65: 33,65 GOOD (HHFFFF)
Size 66: 33,66 GOOD (HHFFFF)
Size 67: 34,67 GOOD (HHFFFF)
Size 68: 34,68 GOOD (HHFFFF)
Size 69: 35,69 GOOD (HHFFFF)
Size 70: 35,70 GOOD (HHFFFF)
Size 71: 36,71 GOOD (HHFFFF)
Size 72: 36,72 GOOD (HHFFFF)
Size 73: 37,73 GOOD (HHFFFF)
Size 74: 37,74 GOOD (HHFFFF)
Size 75: 38,75 GOOD (HHFFFF)
Size 76: 38,76 GOOD (HHFFFF)
Size 77: 39,77 GOOD (HHFFFF)
Size 78: 39,78 GOOD (HHFFFF)
Size 79: 40,79 GOOD (HHFFFF)
Size 80: 40,80 GOOD (HHFFFF)
Size 81: 41,81 GOOD (HHFFFF)
Size 82: 41,82 GOOD (HHFFFF)
Size 83: 42,83 GOOD (HHFFFF)
Size 84: 42,84 GOOD (HHFFFF)
Size 85: 43,85 GOOD (HHFFFF)
Size 86: 43,86 GOOD (HHFFFF)
Size 87: 44,87 GOOD (HHFFFF)
Size 88: 44,88 GOOD (HHFFFF)
Size 89: 45,89 GOOD (HHFFFF)
Size 90: 45,90 GOOD (HHFFFF)
Size 91: 46,91 GOOD (HHFFFF)
Size 92: 46,92 GOOD (HHFFFF)
Size 93: 47,93 GOOD (HHFFFF)
Size 94: 47,94 GOOD (HHFFFF)
Size 95: 48,95 GOOD (HHFFFF)
Size 96: 48,96 GOOD (HHFFFF)
Size 97: 49,97 GOOD (HHFFFF)
Size 98: 49,98 GOOD (HHFFFF)
Size 99: 50,99 GOOD (HHFFFF)
Size 100: 50,100 GOOD (HHFFFF)

View File

@@ -0,0 +1,16 @@
The narrowest allowed console window, in pixels, on a conventional (~96dpi)
monitor:
(mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 1 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12
(mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 16 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12
sz1:px sz1:col sz16:px sz16:col
Vista: 124 104 137 10
Windows 7: 132 112 147 11
Windows 8: 140 120 147 11
Windows 8.1: 140 120 147 11
Windows 10 OLD: 136 116 147 11
Windows 10 NEW: 136 103 136 10
I used build 14342 to test Windows 10.

View File

@@ -0,0 +1,4 @@
As before, avoid odd sizes in favor of even sizes.
It's curious that the Japanese font is handled so poorly, especially with
Windows 8 and later.

View File

@@ -0,0 +1,144 @@
Issues:
- Starting with the 14342 build, changing the font using
SetCurrentConsoleFontEx does not affect the window size. e.g. The content
itself will resize/redraw, but the window neither shrinks nor expands.
Presumably this is an oversight? It's almost a convenience; if a program
is going to resize the window anyway, then it's nice that the window size
contraints don't get in the way. Ordinarily, changing the font doesn't just
change the window size in pixels--it can also change the size as measured in
rows and columns.
- (Aside: in the 14342 build, there is also a bug with wmic.exe. Open a console
with more than 300 lines of screen buffer, then fill those lines with, e.g.,
dir /s. Then run wmic.exe. You won't be able to see the wmic.exe prompt.
If you query the screen buffer info somehow, you'll notice that the srWindow
is not contained within the dwSize. This breaks winpty's scraping, because
it's invalid.)
- In build 14316, with the Japanese locale, with the 437 code page, attempting
to set the Consolas font instead sets the Terminal (raster) font. It seems
to pick an appropriate vertical size.
- It seems necessary to specify "-family 0x36" for maximum reliability.
Setting the family to 0 almost always works, and specifying just -tt rarely
works.
Win7
English locale / 437 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
SetFont.exe -face Consolas -h 16 -family 0x36 works
Japanese locale / 932 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
SetFont.exe -face Consolas -h 16 -family 0x36 works
Japanese locale / 437 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt unreliable
SetFont.exe -face Consolas -h 16 -family 0x36 works
Win10 Build 10586
New console
Japanese locale / 437 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt selects Terminal instead
SetFont.exe -face Consolas -h 16 -family 0x36 works
Win10 Build 14316
Old console
English locale / 437 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
SetFont.exe -face Consolas -h 16 -family 0x36 works
Japanese locale / 932 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
SetFont.exe -face Consolas -h 16 -family 0x36 works
Japanese locale / 437 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt selected very small Consolas font
SetFont.exe -face Consolas -h 16 -family 0x36 works
New console
English locale / 437 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt works
SetFont.exe -face Consolas -h 16 -family 0x36 works
Japanese locale / 932 code page:
SetFont.exe -face Consolas -h 16 selects gothic instead
SetFont.exe -face Consolas -h 16 -tt selects gothic instead
SetFont.exe -face Consolas -h 16 -family 0x36 selects gothic instead
Japanese locale / 437 code page:
SetFont.exe -face Consolas -h 16 selects Terminal font instead
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
SetFont.exe -face Consolas -h 16 -family 0x36(*) selects Terminal font instead
Win10 Build 14342
Old Console
English locale / 437 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
SetFont.exe -face Consolas -h 16 -family 0x36 works
Japanese locale / 932 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
SetFont.exe -face Consolas -h 16 -family 0x36 works
Japanese locale / 437 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead
SetFont.exe -face Consolas -h 16 -family 0x36 works
New console
English locale / 437 code page:
SetFont.exe -face Consolas -h 16 works
SetFont.exe -face Consolas -h 16 -tt works
SetFont.exe -face Consolas -h 16 -family 0x36 works
Japanese locale / 932 code page:
SetFont.exe -face Consolas -h 16 selects gothic instead
SetFont.exe -face Consolas -h 16 -tt selects gothic instead
SetFont.exe -face Consolas -h 16 -family 0x36 selects gothic instead
Japanese locale / 437 code page:
SetFont.exe -face Consolas -h 16 selects Terminal font instead
SetFont.exe -face Consolas -h 16 -tt works
SetFont.exe -face Consolas -h 16 -family 0x36 works
(*) I was trying to figure out whether the inconsistency was at when I stumbled
onto this completely unexpected bug. Here's more detail:
F:\>SetFont.exe -face Consolas -h 16 -family 0x36 -weight normal -w 8
Setting to: nFont=0 dwFontSize=(8,16) FontFamily=0x36 FontWeight=400 FaceName="Consolas"
SetCurrentConsoleFontEx returned 1
F:\>GetFont.exe
largestConsoleWindowSize=(96,50)
maxWnd=0: nFont=0 dwFontSize=(12,16) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
maxWnd=1: nFont=0 dwFontSize=(96,25) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
00-00: 12x16
GetNumberOfConsoleFonts returned 0
CP=437 OutputCP=437
F:\>SetFont.exe -face "Lucida Console" -h 16 -family 0x36 -weight normal
Setting to: nFont=0 dwFontSize=(0,16) FontFamily=0x36 FontWeight=400 FaceName="Lucida Console"
SetCurrentConsoleFontEx returned 1
F:\>GetFont.exe
largestConsoleWindowSize=(96,50)
maxWnd=0: nFont=0 dwFontSize=(12,16) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
maxWnd=1: nFont=0 dwFontSize=(96,25) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
00-00: 12x16
GetNumberOfConsoleFonts returned 0
CP=437 OutputCP=437
F:\>SetFont.exe -face "Lucida Console" -h 12 -family 0x36 -weight normal
Setting to: nFont=0 dwFontSize=(0,12) FontFamily=0x36 FontWeight=400 FaceName="Lucida Console"
SetCurrentConsoleFontEx returned 1
F:\>GetFont.exe
largestConsoleWindowSize=(230,66)
maxWnd=0: nFont=0 dwFontSize=(5,12) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
maxWnd=1: nFont=0 dwFontSize=(116,36) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C)
00-00: 5x12
GetNumberOfConsoleFonts returned 0
CP=437 OutputCP=437
Even attempting to set to a Lucida Console / Consolas font from the Console
properties dialog fails.

View File

@@ -0,0 +1,100 @@
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include "TestUtil.cc"
#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0]))
// See https://en.wikipedia.org/wiki/List_of_CJK_fonts
const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese
const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese
const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese
const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean
std::vector<bool> condense(const std::vector<CHAR_INFO> &buf) {
std::vector<bool> ret;
size_t i = 0;
while (i < buf.size()) {
if (buf[i].Char.UnicodeChar == L' ' &&
((buf[i].Attributes & 0x300) == 0)) {
// end of line
break;
} else if (i + 1 < buf.size() &&
((buf[i].Attributes & 0x300) == 0x100) &&
((buf[i + 1].Attributes & 0x300) == 0x200) &&
buf[i].Char.UnicodeChar != L' ' &&
buf[i].Char.UnicodeChar == buf[i + 1].Char.UnicodeChar) {
// double-width
ret.push_back(true);
i += 2;
} else if ((buf[i].Attributes & 0x300) == 0) {
// single-width
ret.push_back(false);
i++;
} else {
ASSERT(false && "unexpected output");
}
}
return ret;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s \"arguments for SetFont.exe\"\n", argv[0]);
return 1;
}
const char *setFontArgs = argv[1];
const wchar_t testLine[] = { 0xA2, 0xA3, 0x2014, 0x3044, 0x30FC, 0x4000, 0 };
const HANDLE conout = openConout();
char setFontCmd[1024];
for (int h = 1; h <= 100; ++h) {
sprintf(setFontCmd, ".\\SetFont.exe %s -h %d && cls", setFontArgs, h);
system(setFontCmd);
CONSOLE_FONT_INFOEX infoex = {};
infoex.cbSize = sizeof(infoex);
BOOL success = GetCurrentConsoleFontEx(conout, FALSE, &infoex);
ASSERT(success && "GetCurrentConsoleFontEx failed");
DWORD actual = 0;
success = WriteConsoleW(conout, testLine, wcslen(testLine), &actual, nullptr);
ASSERT(success && actual == wcslen(testLine));
std::vector<CHAR_INFO> readBuf(14);
const SMALL_RECT readRegion = {0, 0, static_cast<short>(readBuf.size() - 1), 0};
SMALL_RECT readRegion2 = readRegion;
success = ReadConsoleOutputW(
conout, readBuf.data(),
{static_cast<short>(readBuf.size()), 1},
{0, 0},
&readRegion2);
ASSERT(success && !memcmp(&readRegion, &readRegion2, sizeof(readRegion)));
const auto widths = condense(readBuf);
std::string widthsStr;
for (bool width : widths) {
widthsStr.append(width ? "F" : "H");
}
char size[16];
sprintf(size, "%d,%d", infoex.dwFontSize.X, infoex.dwFontSize.Y);
const char *status = "";
if (widthsStr == "HHFFFF") {
status = "GOOD";
} else if (widthsStr == "HHHFFF") {
status = "OK";
} else {
status = "BAD";
}
trace("Size %3d: %-7s %-4s (%s)", h, size, status, widthsStr.c_str());
}
sprintf(setFontCmd, ".\\SetFont.exe %s -h 14", setFontArgs);
system(setFontCmd);
}

View File

@@ -0,0 +1,21 @@
#include <ctype.h>
#include <stdio.h>
#include <string.h>
static inline void formatChar(char *str, char ch)
{
// Print some common control codes.
switch (ch) {
case '\r': strcpy(str, "CR "); break;
case '\n': strcpy(str, "LF "); break;
case ' ': strcpy(str, "SP "); break;
case 27: strcpy(str, "^[ "); break;
case 3: strcpy(str, "^C "); break;
default:
if (isgraph(ch))
sprintf(str, "%c ", ch);
else
sprintf(str, "%02x ", ch);
break;
}
}

View File

@@ -0,0 +1,62 @@
#include <windows.h>
#include "TestUtil.cc"
const int SC_CONSOLE_MARK = 0xFFF2;
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
int main(int argc, char *argv[0]) {
if (argc != 2) {
printf("Usage: %s (mark|selectall|read)\n", argv[0]);
return 1;
}
enum class Test { Mark, SelectAll, Read } test;
if (!strcmp(argv[1], "mark")) {
test = Test::Mark;
} else if (!strcmp(argv[1], "selectall")) {
test = Test::SelectAll;
} else if (!strcmp(argv[1], "read")) {
test = Test::Read;
} else {
printf("Invalid test: %s\n", argv[1]);
return 1;
}
HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
TimeMeasurement tm;
HWND hwnd = GetConsoleWindow();
setWindowPos(0, 0, 1, 1);
setBufferSize(100, 3000);
system("cls");
setWindowPos(0, 2975, 100, 25);
setCursorPos(0, 2999);
ShowWindow(hwnd, SW_HIDE);
for (int i = 0; i < 1000; ++i) {
// CONSOLE_SCREEN_BUFFER_INFO info = {};
// GetConsoleScreenBufferInfo(conout, &info);
if (test == Test::Mark) {
SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0);
SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
} else if (test == Test::SelectAll) {
SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0);
SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
} else if (test == Test::Read) {
static CHAR_INFO buffer[100 * 3000];
const SMALL_RECT readRegion = {0, 0, 99, 2999};
SMALL_RECT tmp = readRegion;
BOOL ret = ReadConsoleOutput(conout, buffer, {100, 3000}, {0, 0}, &tmp);
ASSERT(ret && !memcmp(&tmp, &readRegion, sizeof(tmp)));
}
}
ShowWindow(hwnd, SW_SHOW);
printf("elapsed: %f\n", tm.elapsed());
return 0;
}

20
src/libs/3rdparty/winpty/misc/GetCh.cc vendored Normal file
View File

@@ -0,0 +1,20 @@
#include <conio.h>
#include <ctype.h>
#include <stdio.h>
int main() {
printf("\nPress any keys -- Ctrl-D exits\n\n");
while (true) {
const int ch = getch();
printf("0x%x", ch);
if (isgraph(ch)) {
printf(" '%c'", ch);
}
printf("\n");
if (ch == 0x4) { // Ctrl-D
break;
}
}
return 0;
}

View File

@@ -0,0 +1,41 @@
#include <windows.h>
#include <stdio.h>
#include "TestUtil.cc"
int main() {
const HANDLE conout = openConout();
CONSOLE_SCREEN_BUFFER_INFO info = {};
BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
ASSERT(ret && "GetConsoleScreenBufferInfo failed");
trace("cursor=%d,%d", info.dwCursorPosition.X, info.dwCursorPosition.Y);
printf("cursor=%d,%d\n", info.dwCursorPosition.X, info.dwCursorPosition.Y);
trace("srWindow={L=%d,T=%d,R=%d,B=%d}", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom);
printf("srWindow={L=%d,T=%d,R=%d,B=%d}\n", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom);
trace("dwSize=%d,%d", info.dwSize.X, info.dwSize.Y);
printf("dwSize=%d,%d\n", info.dwSize.X, info.dwSize.Y);
const HWND hwnd = GetConsoleWindow();
if (hwnd != NULL) {
RECT r = {};
if (GetWindowRect(hwnd, &r)) {
const int w = r.right - r.left;
const int h = r.bottom - r.top;
trace("hwnd: pos=(%d,%d) size=(%d,%d)", r.left, r.top, w, h);
printf("hwnd: pos=(%d,%d) size=(%d,%d)\n", r.left, r.top, w, h);
} else {
trace("GetWindowRect failed");
printf("GetWindowRect failed\n");
}
} else {
trace("GetConsoleWindow returned NULL");
printf("GetConsoleWindow returned NULL\n");
}
return 0;
}

261
src/libs/3rdparty/winpty/misc/GetFont.cc vendored Normal file
View File

@@ -0,0 +1,261 @@
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>
#include "../src/shared/OsModule.h"
#include "../src/shared/StringUtil.h"
#include "TestUtil.cc"
#include "../src/shared/StringUtil.cc"
#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
// Some of these types and functions are missing from the MinGW headers.
// Others are undocumented.
struct AGENT_CONSOLE_FONT_INFO {
DWORD nFont;
COORD dwFontSize;
};
struct AGENT_CONSOLE_FONT_INFOEX {
ULONG cbSize;
DWORD nFont;
COORD dwFontSize;
UINT FontFamily;
UINT FontWeight;
WCHAR FaceName[LF_FACESIZE];
};
// undocumented XP API
typedef BOOL WINAPI SetConsoleFont_t(
HANDLE hOutput,
DWORD dwFontIndex);
// undocumented XP API
typedef DWORD WINAPI GetNumberOfConsoleFonts_t();
// XP and up
typedef BOOL WINAPI GetCurrentConsoleFont_t(
HANDLE hOutput,
BOOL bMaximumWindow,
AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont);
// XP and up
typedef COORD WINAPI GetConsoleFontSize_t(
HANDLE hConsoleOutput,
DWORD nFont);
// Vista and up
typedef BOOL WINAPI GetCurrentConsoleFontEx_t(
HANDLE hConsoleOutput,
BOOL bMaximumWindow,
AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
// Vista and up
typedef BOOL WINAPI SetCurrentConsoleFontEx_t(
HANDLE hConsoleOutput,
BOOL bMaximumWindow,
AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
#define GET_MODULE_PROC(mod, funcName) \
m_##funcName = reinterpret_cast<funcName##_t*>((mod).proc(#funcName)); \
#define DEFINE_ACCESSOR(funcName) \
funcName##_t &funcName() const { \
ASSERT(valid()); \
return *m_##funcName; \
}
class XPFontAPI {
public:
XPFontAPI() : m_kernel32(L"kernel32.dll") {
GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFont);
GET_MODULE_PROC(m_kernel32, GetConsoleFontSize);
}
bool valid() const {
return m_GetCurrentConsoleFont != NULL &&
m_GetConsoleFontSize != NULL;
}
DEFINE_ACCESSOR(GetCurrentConsoleFont)
DEFINE_ACCESSOR(GetConsoleFontSize)
private:
OsModule m_kernel32;
GetCurrentConsoleFont_t *m_GetCurrentConsoleFont;
GetConsoleFontSize_t *m_GetConsoleFontSize;
};
class UndocumentedXPFontAPI : public XPFontAPI {
public:
UndocumentedXPFontAPI() : m_kernel32(L"kernel32.dll") {
GET_MODULE_PROC(m_kernel32, SetConsoleFont);
GET_MODULE_PROC(m_kernel32, GetNumberOfConsoleFonts);
}
bool valid() const {
return this->XPFontAPI::valid() &&
m_SetConsoleFont != NULL &&
m_GetNumberOfConsoleFonts != NULL;
}
DEFINE_ACCESSOR(SetConsoleFont)
DEFINE_ACCESSOR(GetNumberOfConsoleFonts)
private:
OsModule m_kernel32;
SetConsoleFont_t *m_SetConsoleFont;
GetNumberOfConsoleFonts_t *m_GetNumberOfConsoleFonts;
};
class VistaFontAPI : public XPFontAPI {
public:
VistaFontAPI() : m_kernel32(L"kernel32.dll") {
GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFontEx);
GET_MODULE_PROC(m_kernel32, SetCurrentConsoleFontEx);
}
bool valid() const {
return this->XPFontAPI::valid() &&
m_GetCurrentConsoleFontEx != NULL &&
m_SetCurrentConsoleFontEx != NULL;
}
DEFINE_ACCESSOR(GetCurrentConsoleFontEx)
DEFINE_ACCESSOR(SetCurrentConsoleFontEx)
private:
OsModule m_kernel32;
GetCurrentConsoleFontEx_t *m_GetCurrentConsoleFontEx;
SetCurrentConsoleFontEx_t *m_SetCurrentConsoleFontEx;
};
static std::vector<std::pair<DWORD, COORD> > readFontTable(
XPFontAPI &api, HANDLE conout, DWORD maxCount) {
std::vector<std::pair<DWORD, COORD> > ret;
for (DWORD i = 0; i < maxCount; ++i) {
COORD size = api.GetConsoleFontSize()(conout, i);
if (size.X == 0 && size.Y == 0) {
break;
}
ret.push_back(std::make_pair(i, size));
}
return ret;
}
static void dumpFontTable(HANDLE conout) {
const int kMaxCount = 1000;
XPFontAPI api;
if (!api.valid()) {
printf("dumpFontTable: cannot dump font table -- missing APIs\n");
return;
}
std::vector<std::pair<DWORD, COORD> > table =
readFontTable(api, conout, kMaxCount);
std::string line;
char tmp[128];
size_t first = 0;
while (first < table.size()) {
size_t last = std::min(table.size() - 1, first + 10 - 1);
winpty_snprintf(tmp, "%02u-%02u:",
static_cast<unsigned>(first), static_cast<unsigned>(last));
line = tmp;
for (size_t i = first; i <= last; ++i) {
if (i % 10 == 5) {
line += " - ";
}
winpty_snprintf(tmp, " %2dx%-2d",
table[i].second.X, table[i].second.Y);
line += tmp;
}
printf("%s\n", line.c_str());
first = last + 1;
}
if (table.size() == kMaxCount) {
printf("... stopped reading at %d fonts ...\n", kMaxCount);
}
}
static std::string stringToCodePoints(const std::wstring &str) {
std::string ret = "(";
for (size_t i = 0; i < str.size(); ++i) {
char tmp[32];
winpty_snprintf(tmp, "%X", str[i]);
if (ret.size() > 1) {
ret.push_back(' ');
}
ret += tmp;
}
ret.push_back(')');
return ret;
}
static void dumpFontInfoEx(
const AGENT_CONSOLE_FONT_INFOEX &infoex) {
std::wstring faceName(infoex.FaceName,
winpty_wcsnlen(infoex.FaceName, COUNT_OF(infoex.FaceName)));
cprintf(L"nFont=%u dwFontSize=(%d,%d) "
"FontFamily=0x%x FontWeight=%u FaceName=%ls %hs\n",
static_cast<unsigned>(infoex.nFont),
infoex.dwFontSize.X, infoex.dwFontSize.Y,
infoex.FontFamily, infoex.FontWeight, faceName.c_str(),
stringToCodePoints(faceName).c_str());
}
static void dumpVistaFont(VistaFontAPI &api, HANDLE conout, BOOL maxWindow) {
AGENT_CONSOLE_FONT_INFOEX infoex = {0};
infoex.cbSize = sizeof(infoex);
if (!api.GetCurrentConsoleFontEx()(conout, maxWindow, &infoex)) {
printf("GetCurrentConsoleFontEx call failed\n");
return;
}
dumpFontInfoEx(infoex);
}
static void dumpXPFont(XPFontAPI &api, HANDLE conout, BOOL maxWindow) {
AGENT_CONSOLE_FONT_INFO info = {0};
if (!api.GetCurrentConsoleFont()(conout, maxWindow, &info)) {
printf("GetCurrentConsoleFont call failed\n");
return;
}
printf("nFont=%u dwFontSize=(%d,%d)\n",
static_cast<unsigned>(info.nFont),
info.dwFontSize.X, info.dwFontSize.Y);
}
static void dumpFontAndTable(HANDLE conout) {
VistaFontAPI vista;
if (vista.valid()) {
printf("maxWnd=0: "); dumpVistaFont(vista, conout, FALSE);
printf("maxWnd=1: "); dumpVistaFont(vista, conout, TRUE);
dumpFontTable(conout);
return;
}
UndocumentedXPFontAPI xp;
if (xp.valid()) {
printf("maxWnd=0: "); dumpXPFont(xp, conout, FALSE);
printf("maxWnd=1: "); dumpXPFont(xp, conout, TRUE);
dumpFontTable(conout);
return;
}
printf("setSmallFont: neither Vista nor XP APIs detected -- giving up\n");
dumpFontTable(conout);
}
int main() {
const HANDLE conout = openConout();
const COORD largest = GetLargestConsoleWindowSize(conout);
printf("largestConsoleWindowSize=(%d,%d)\n", largest.X, largest.Y);
dumpFontAndTable(conout);
UndocumentedXPFontAPI xp;
if (xp.valid()) {
printf("GetNumberOfConsoleFonts returned %u\n", xp.GetNumberOfConsoleFonts()());
} else {
printf("The GetNumberOfConsoleFonts API was missing\n");
}
printf("CP=%u OutputCP=%u\n", GetConsoleCP(), GetConsoleOutputCP());
return 0;
}

View File

@@ -0,0 +1,51 @@
#
# Usage: powershell <path>\IdentifyConsoleWindow.ps1
#
# This script determines whether the process has a console attached, whether
# that console has a non-NULL window (e.g. HWND), and whether the window is on
# the current window station.
#
$signature = @'
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool SetConsoleTitle(String title);
[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int GetWindowText(IntPtr hWnd,
System.Text.StringBuilder lpString,
int nMaxCount);
'@
$WinAPI = Add-Type -MemberDefinition $signature `
-Name WinAPI -Namespace IdentifyConsoleWindow -PassThru
if (!$WinAPI::SetConsoleTitle("ConsoleWindowScript")) {
echo "error: could not change console title -- is a console attached?"
exit 1
} else {
echo "note: successfully set console title to ""ConsoleWindowScript""."
}
$hwnd = $WinAPI::GetConsoleWindow()
if ($hwnd -eq 0) {
echo "note: GetConsoleWindow returned NULL."
} else {
echo "note: GetConsoleWindow returned 0x$($hwnd.ToString("X"))."
$sb = New-Object System.Text.StringBuilder -ArgumentList 4096
if ($WinAPI::GetWindowText($hwnd, $sb, $sb.Capacity)) {
$title = $sb.ToString()
echo "note: GetWindowText returned ""${title}""."
if ($title -eq "ConsoleWindowScript") {
echo "success!"
} else {
echo "error: expected to see ""ConsoleWindowScript""."
echo " (Perhaps the console window is on a different window station?)"
}
} else {
echo "error: GetWindowText could not read the window title."
echo " (Perhaps the console window is on a different window station?)"
}
}

View File

@@ -0,0 +1,87 @@
// Determines whether this is a new console by testing whether MARK moves the
// cursor.
//
// WARNING: This test program may behave erratically if run under winpty.
//
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "TestUtil.cc"
const int SC_CONSOLE_MARK = 0xFFF2;
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
static COORD getWindowPos(HANDLE conout) {
CONSOLE_SCREEN_BUFFER_INFO info = {};
BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
ASSERT(ret && "GetConsoleScreenBufferInfo failed");
return { info.srWindow.Left, info.srWindow.Top };
}
static COORD getWindowSize(HANDLE conout) {
CONSOLE_SCREEN_BUFFER_INFO info = {};
BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
ASSERT(ret && "GetConsoleScreenBufferInfo failed");
return {
static_cast<short>(info.srWindow.Right - info.srWindow.Left + 1),
static_cast<short>(info.srWindow.Bottom - info.srWindow.Top + 1)
};
}
static COORD getCursorPos(HANDLE conout) {
CONSOLE_SCREEN_BUFFER_INFO info = {};
BOOL ret = GetConsoleScreenBufferInfo(conout, &info);
ASSERT(ret && "GetConsoleScreenBufferInfo failed");
return info.dwCursorPosition;
}
static void setCursorPos(HANDLE conout, COORD pos) {
BOOL ret = SetConsoleCursorPosition(conout, pos);
ASSERT(ret && "SetConsoleCursorPosition failed");
}
int main() {
const HANDLE conout = openConout();
const HWND hwnd = GetConsoleWindow();
ASSERT(hwnd != NULL && "GetConsoleWindow() returned NULL");
// With the legacy console, the Mark command moves the the cursor to the
// top-left cell of the visible console window. Determine whether this
// is the new console by seeing if the cursor moves.
const auto windowSize = getWindowSize(conout);
if (windowSize.X <= 1) {
printf("Error: console window must be at least 2 columns wide\n");
trace("Error: console window must be at least 2 columns wide");
return 1;
}
bool cursorMoved = false;
const auto initialPos = getCursorPos(conout);
const auto windowPos = getWindowPos(conout);
setCursorPos(conout, { static_cast<short>(windowPos.X + 1), windowPos.Y });
{
const auto posA = getCursorPos(conout);
SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0);
const auto posB = getCursorPos(conout);
cursorMoved = memcmp(&posA, &posB, sizeof(posA)) != 0;
SendMessage(hwnd, WM_CHAR, 27, 0x00010001); // Send ESCAPE
}
setCursorPos(conout, initialPos);
if (cursorMoved) {
printf("Legacy console (i.e. MARK moved cursor)\n");
trace("Legacy console (i.e. MARK moved cursor)");
} else {
printf("Windows 10 new console (i.e MARK did not move cursor)\n");
trace("Windows 10 new console (i.e MARK did not move cursor)");
}
return 0;
}

View File

@@ -0,0 +1,90 @@
Introduction
============
The only specification I could find describing mouse input escape sequences
was the /usr/share/doc/xterm/ctlseqs.txt.gz file installed on my Ubuntu
machine.
Here are the relevant escape sequences:
* [ON] CSI '?' M 'h' Enable mouse input mode M
* [OFF] CSI '?' M 'l' Disable mouse input mode M
* [EVT] CSI 'M' F X Y Mouse event (default or mode 1005)
* [EVT6] CSI '<' F ';' X ';' Y 'M' Mouse event with mode 1006
* [EVT6] CSI '<' F ';' X ';' Y 'm' Mouse event with mode 1006 (up)
* [EVT15] CSI F ';' X ';' Y 'M' Mouse event with mode 1015
The first batch of modes affect what events are reported:
* 9: Presses only (not as well-supported as the other modes)
* 1000: Presses and releases
* 1002: Presses, releases, and moves-while-pressed
* 1003: Presses, releases, and all moves
The next batch of modes affect the encoding of the mouse events:
* 1005: The X and Y coordinates are UTF-8 codepoints rather than bytes.
* 1006: Use the EVT6 sequences instead of EVT
* 1015: Use the EVT15 sequence instead of EVT (aka URVXT-mode)
Support for modes in existing terminals
=======================================
| 9 1000 1002 1003 | 1004 | overflow | defhi | 1005 1006 1015
---------------------------------+---------------------+------+--------------+-------+----------------
Eclipse TM Terminal (Neon) | _ _ _ _ | _ | n/a | n/a | _ _ _
gnome-terminal 3.6.2 | X X X X | _ | suppressed*b | 0x07 | _ X X
iTerm2 2.1.4 | _ X X X | OI | wrap*z | n/a | X X X
jediterm/IntelliJ | _ X X X | _ | ch='?' | 0xff | X X X
Konsole 2.13.2 | _ X X *a | _ | suppressed | 0xff | X X X
mintty 2.2.2 | X X X X | OI | ch='\0' | 0xff | X X X
putty 0.66 | _ X X _ | _ | suppressed | 0xff | _ X X
rxvt 2.7.10 | X X _ _ | _ | wrap*z | n/a | _ _ _
screen(under xterm) | X X X X | _ | suppressed | 0xff | _ _ _
urxvt 9.21 | X X X X | _ | wrap*z | n/a | X _ X
xfce4-terminal 0.6.3 (GTK2 VTE) | X X X X | _ | wrap | n/a | _ _ _
xterm | X X X X | OI | ch='\0' | 0xff | X X X
*a: Mode 1003 is handled the same way as 1002.
*b: The coordinate wraps from 0xff to 0x00, then maxs out at 0x07. I'm
guessing this behavior is a bug? I'm using the Xubuntu 14.04
gnome-terminal.
*z: These terminals have a bug where column 224 (and row 224, presumably)
yields a truncated escape sequence. 224 + 32 is 0, so it would normally
yield `CSI 'M' F '\0' Y`, but the '\0' is interpreted as a NUL-terminator.
Problem 1: How do these flags work?
===================================
Terminals accept the OFF sequence with any of the input modes. This makes
little sense--there are two multi-value settings, not seven independent flags!
All the terminals handle Granularity the same way. ON-Granularity sets
Granularity to the specified value, and OFF-Granularity sets Granularity to
OFF.
Terminals vary in how they handle the Encoding modes. For example:
* xterm. ON-Encoding sets Encoding. OFF-Encoding with a non-active Encoding
has no effect. OFF-Encoding otherwise resets Encoding to Default.
* mintty (tested 2.2.2), iTerm2 2.1.4, and jediterm. ON-Encoding sets
Encoding. OFF-Encoding resets Encoding to Default.
* Konsole (tested 2.13.2) seems to configure each encoding method
independently. The effective Encoding is the first enabled encoding in this
list:
- Mode 1006
- Mode 1015
- Mode 1005
- Default
* gnome-terminal (tested 3.6.2) also configures each encoding method
independently. The effective Encoding is the first enabled encoding in
this list:
- Mode 1006
- Mode 1015
- Default
Mode 1005 is not supported.
* xfce4 terminal 0.6.3 (GTK2 VTE) always outputs the default encoding method.

View File

@@ -0,0 +1,34 @@
#include <windows.h>
#include "TestUtil.cc"
int main(int argc, char *argv[]) {
if (argc != 3 && argc != 5) {
printf("Usage: %s x y\n", argv[0]);
printf("Usage: %s x y width height\n", argv[0]);
return 1;
}
HWND hwnd = GetConsoleWindow();
const int x = atoi(argv[1]);
const int y = atoi(argv[2]);
int w = 0, h = 0;
if (argc == 3) {
RECT r = {};
BOOL ret = GetWindowRect(hwnd, &r);
ASSERT(ret && "GetWindowRect failed on console window");
w = r.right - r.left;
h = r.bottom - r.top;
} else {
w = atoi(argv[3]);
h = atoi(argv[4]);
}
BOOL ret = MoveWindow(hwnd, x, y, w, h, TRUE);
trace("MoveWindow: ret=%d", ret);
printf("MoveWindow: ret=%d\n", ret);
return 0;
}

219
src/libs/3rdparty/winpty/misc/Notes.txt vendored Normal file
View File

@@ -0,0 +1,219 @@
Test programs
-------------
Cygwin
emacs
vim
mc (Midnight Commander)
lynx
links
less
more
wget
Capturing the console output
----------------------------
Initial idea:
In the agent, keep track of the remote terminal state for N lines of
(window+history). Also keep track of the terminal size. Regularly poll for
changes to the console screen buffer, then use some number of edits to bring
the remote terminal into sync with the console.
This idea seems to have trouble when a Unix terminal is resized. When the
server receives a resize notification, it can have a hard time figuring out
what the terminal did. Race conditions might also be a problem.
The behavior of the terminal can be tricky:
- When the window is expanded by one line, does the terminal add a blank line
to the bottom or move a line from the history into the top?
- When the window is shrunk by one line, does the terminal delete the topmost
or the bottommost line? Can it delete the line with the cursor?
Some popular behaviors for expanding:
- [all] If there are no history lines, then add a line at the bottom.
- [konsole] Always add a line at the bottom.
- [putty,xterm,rxvt] Pull in a history line from the top.
- [g-t] I can't tell. It seems to add a blank line, until the program writes
to stdout or until I click the scroll bar, then the output "snaps" back down,
pulling lines out of the history. I thought I saw different behavior
between Ubuntu 10.10 and 11.10, so maybe GNOME 3 changed something. Avoid
using "bash" to test this behavior because "bash" apparently always writes
the prompt after terminal resize.
Some popular behaviors for shrinking:
- [konsole,putty,xterm,rxvt] If the line at the bottom is blank, then delete
it. Otherwise, move the topmost line into history.
- [g-t] If the line at the bottom has not been touched, then delete it.
Otherwise, move the topmost line into history.
(TODO: I need to test my theories about the terminal behavior better still.
It's interesting to see how g-t handles clear differently than every other
terminal.)
There is an ANSI escape sequence (DSR) that sends the current cursor location
to the terminal's input. One idea I had was to use this code to figure out how
the terminal had handled a resize. I currently think this idea won't work due
to race conditions.
Newer idea:
Keep track of the last N lines that have been sent to the remote terminal.
Poll for changes to console output. When the output changes, send just the
changed content to the terminal. In particular:
- Don't send a cursor position (CUP) code. Instead, if the line that's 3
steps up from the latest line changes, send a relative cursor up (CUU)
code. It's OK to send an absolute column number code (CHA).
- At least in general, don't try to send complete screenshots of the current
console window.
The idea is that sending just the changes should have good behavior for streams
of output, even when those streams modify the output (e.g. an archiver, or
maybe a downloader/packager/wget). I need to think about whether this works
for full-screen programs (e.g. emacs, less, lynx, the above list of programs).
I noticed that console programs don't typically modify the window or buffer
coordinates. edit.com is an exception.
I tested the pager in native Python (more?), and I verified that ENTER and SPACE
both paid no attention to the location of the console window within the screen
buffer. This makes sense -- why would they care? The Cygwin less, on the other
hand, does care. If I scroll the window up, then Cygwin less will write to a
position within the window. I didn't really expect this behavior, but it
doesn't seem to be a problem.
Setting up a TestNetServer service
----------------------------------
First run the deploy.sh script to copy files into deploy. Make sure
TestNetServer.exe will run in a bare environment (no MinGW or Qt in the path).
Install the Windows Server 2003 Resource Kit. It will have two programs in it,
instsrv and srvany.
Run:
InstSrv TestNetServer <path-to-srvany>\srvany.exe
This creates a service named "TestNetServer" that uses the Microsoft service
wrapper. To configure the new service to run TestNetServer, set a registry
value:
[HKLM\SYSTEM\CurrentControlSet\Services\TestNetServer\Parameters]
Application=<full-path>\TestNetServer.exe
Also see http://www.iopus.com/guides/srvany.htm.
To remove the service, run:
InstSrv TestNetServer REMOVE
TODO
----
Agent: When resizing the console, consider whether to add lines to the top
or bottom. I remember thinking the current behavior was wrong for some
application, but I forgot which one.
Make the font as small as possible. The console window dimensions are limited by
the screen size, so making the font small reduces an unnecessary limitation on the
PseudoConsole size. There's a documented Vista/Win7 API for this
(SetCurrentConsoleFontEx), and apparently WinXP has an undocumented API
(SetConsoleFont):
http://blogs.microsoft.co.il/blogs/pavely/archive/2009/07/23/changing-console-fonts.aspx
Make the agent work with DOS programs like edit and qbasic.
- Detect that the terminal program has resized the window/buffer and enter a
simple just-scrape-and-dont-resize mode. Track the client window size and
send the intersection of the console and the agent's client.
- I also need to generate keyboard scan codes.
- Solve the NTVDM.EXE console shutdown problem, probably by ignoring NTVDM.EXE
when it appears on the GetConsoleProcessList list.
Rename the agent? Is the term "proxy" more accurate?
Optimize the polling. e.g. Use a longer poll interval when the console is idle.
Do a minimal poll that checks whether the sync marker or window has moved.
Increase the console buffer size to ~9000 lines. Beware making it so big that
reading the sync column exhausts the 32KB conhost<->agent heap.
Reduce the memory overhead of the agent. The agent's m_bufferData array can
be small (a few hundred lines?) relative to the console buffer size.
Try to handle console background color better.
Unix terminal emulators have a user-configurable foreground and background
color, and for best results, the agent really needs to avoid changing the colors,
especially the background color. It's undesirable/ugly to SSH into a machine
and see the command prompt change the colors. It's especially ugly that the
terminal retains its original colors and only drawn cells get the new colors.
(e.g. Resizing the window to the right uses the local terminal colors rather
than the remote colors.) It's especially ugly in gnome-terminal, which draws
user-configurable black as black, but VT100 black as dark-gray.
If there were a way to query the terminal emulator's colors, then I could
match the console's colors to the terminal and everything would just work. As
far as I know, that's not possible.
I thought of a kludge that might work. Instead of translating console white
and black to VT/100 white and black, I would translate them to "reset" and
"invert". I'd translate other colors normally. This approach should produce
ideal results for command-line work and tolerable results for full-screen
programs without configuration. Configuring the agent for black-on-white or
white-on-black would produce ideal results in all situations.
This kludge only really applies to the SSH application. For a Win32 Konsole
application, it should be easy to get the colors right all the time.
Try using the screen reader API:
- To eliminate polling.
- To detect when a line wraps. When a line wraps, it'd be nice not to send a
CRLF to the terminal emulator so copy-and-paste works better.
- To detect hard tabs with Cygwin.
Implement VT100/ANSI escape sequence recognition for input. Decide where this
functionality belongs. PseudoConsole.dll? Disambiguating ESC from an escape
sequence might be tricky. For the SSH server, I was thinking that when a small
SSH payload ended with an ESC character, I could assume the character was really
an ESC keypress, on the assumption that if it were an escape sequence, the
payload would probably contain the whole sequence. I'm not sure this works,
especially if there's a lot of other traffic multiplexed on the SSH socket.
Support Unicode.
- Some DOS programs draw using line/box characters. Can these characters be
translated to the Unicode equivalents?
Create automated tests.
Experiment with the Terminator emulator, an emulator that doesn't wrap lines.
How many columns does it report having? What column does it report the cursor
in as it's writing past the right end of the window? Will Terminator be a
problem if I implement line wrapping detection in the agent?
BUG: After the unix-adapter/pconsole.exe program exits, the blinking cursor is
replaced with a hidden cursor.
Fix assert() in the agent. If it fails, the failure message needs to be
reported somewhere. Pop up a dialog box? Maybe switch the active desktop,
then show a dialog box?
TODO: There's already a pconsole project on GitHub. Maybe rename this project
to something else? winpty?
TODO: Can the DebugServer system be replaced with OutputDebugString? How
do we decide whose processes' output to collect?
TODO: Three executables:
build/winpty-agent.exe
build/winpty.dll
build/console.exe
BUG: Run the pconsole.exe inside another console. As I type dir, I see this:
D:\rprichard\pconsole>
D:\rprichard\pconsole>d
D:\rprichard\pconsole>di
D:\rprichard\pconsole>dir
In the output of "dir", every other line is blank.
There was a bug in Terminal::sendLine that was causing this to happen
frequently. Now that I fixed it, this bug should only manifest on lines
whose last column is not a space (i.e. a full line).

View File

@@ -0,0 +1,27 @@
#include <windows.h>
#include <assert.h>
#include <locale.h>
#include <stdio.h>
#include <iostream>
int main() {
setlocale(LC_ALL, "");
OSVERSIONINFOEXW info = {0};
info.dwOSVersionInfoSize = sizeof(info);
assert(GetVersionExW((OSVERSIONINFOW*)&info));
printf("dwMajorVersion = %d\n", (int)info.dwMajorVersion);
printf("dwMinorVersion = %d\n", (int)info.dwMinorVersion);
printf("dwBuildNumber = %d\n", (int)info.dwBuildNumber);
printf("dwPlatformId = %d\n", (int)info.dwPlatformId);
printf("szCSDVersion = %ls\n", info.szCSDVersion);
printf("wServicePackMajor = %d\n", info.wServicePackMajor);
printf("wServicePackMinor = %d\n", info.wServicePackMinor);
printf("wSuiteMask = 0x%x\n", (unsigned int)info.wSuiteMask);
printf("wProductType = 0x%x\n", (unsigned int)info.wProductType);
return 0;
}

View File

@@ -0,0 +1,101 @@
//
// Verify that console selection blocks writes to an inactive console screen
// buffer. Writes TEST PASSED or TEST FAILED to the popup console window.
//
#include <windows.h>
#include <stdio.h>
#include <string>
#include "TestUtil.cc"
const int SC_CONSOLE_MARK = 0xFFF2;
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
bool g_useMark = false;
CALLBACK DWORD pausingThread(LPVOID dummy)
{
HWND hwnd = GetConsoleWindow();
trace("Sending selection to freeze");
SendMessage(hwnd, WM_SYSCOMMAND,
g_useMark ? SC_CONSOLE_MARK :
SC_CONSOLE_SELECT_ALL,
0);
Sleep(1000);
trace("Sending escape WM_CHAR to unfreeze");
SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
Sleep(1000);
}
static HANDLE createBuffer() {
HANDLE buf = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL);
ASSERT(buf != INVALID_HANDLE_VALUE);
return buf;
}
static void runTest(bool useMark, bool createEarly) {
trace("=======================================");
trace("useMark=%d createEarly=%d", useMark, createEarly);
g_useMark = useMark;
HANDLE buf = INVALID_HANDLE_VALUE;
if (createEarly) {
buf = createBuffer();
}
CreateThread(NULL, 0,
pausingThread, NULL,
0, NULL);
Sleep(500);
if (!createEarly) {
trace("Creating buffer");
TimeMeasurement tm1;
buf = createBuffer();
const double elapsed1 = tm1.elapsed();
if (elapsed1 >= 0.250) {
printf("!!! TEST FAILED !!!\n");
Sleep(2000);
return;
}
}
trace("Writing to aux buffer");
TimeMeasurement tm2;
DWORD actual = 0;
BOOL ret = WriteConsoleW(buf, L"HI", 2, &actual, NULL);
const double elapsed2 = tm2.elapsed();
trace("Writing to aux buffer: finished: ret=%d actual=%d (elapsed=%1.3f)", ret, actual, elapsed2);
if (elapsed2 < 0.250) {
printf("!!! TEST FAILED !!!\n");
} else {
printf("TEST PASSED\n");
}
Sleep(2000);
}
int main(int argc, char **argv) {
if (argc == 1) {
startChildProcess(L"child");
return 0;
}
std::string arg = argv[1];
if (arg == "child") {
for (int useMark = 0; useMark <= 1; useMark++) {
for (int createEarly = 0; createEarly <= 1; createEarly++) {
runTest(useMark, createEarly);
}
}
printf("done...\n");
Sleep(1000);
}
return 0;
}

View File

@@ -0,0 +1,671 @@
//
// Windows versions tested
//
// Vista Enterprise SP2 32-bit
// - ver reports [Version 6.0.6002]
// - kernel32.dll product/file versions are 6.0.6002.19381
//
// Windows 7 Ultimate SP1 32-bit
// - ver reports [Version 6.1.7601]
// - conhost.exe product/file versions are 6.1.7601.18847
// - kernel32.dll product/file versions are 6.1.7601.18847
//
// Windows Server 2008 R2 Datacenter SP1 64-bit
// - ver reports [Version 6.1.7601]
// - conhost.exe product/file versions are 6.1.7601.23153
// - kernel32.dll product/file versions are 6.1.7601.23153
//
// Windows 8 Enterprise 32-bit
// - ver reports [Version 6.2.9200]
// - conhost.exe product/file versions are 6.2.9200.16578
// - kernel32.dll product/file versions are 6.2.9200.16859
//
//
// Specific version details on working Server 2008 R2:
//
// dwMajorVersion = 6
// dwMinorVersion = 1
// dwBuildNumber = 7601
// dwPlatformId = 2
// szCSDVersion = Service Pack 1
// wServicePackMajor = 1
// wServicePackMinor = 0
// wSuiteMask = 0x190
// wProductType = 0x3
//
// Specific version details on broken Win7:
//
// dwMajorVersion = 6
// dwMinorVersion = 1
// dwBuildNumber = 7601
// dwPlatformId = 2
// szCSDVersion = Service Pack 1
// wServicePackMajor = 1
// wServicePackMinor = 0
// wSuiteMask = 0x100
// wProductType = 0x1
//
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "TestUtil.cc"
const char *g_prefix = "";
static void dumpHandles() {
trace("%sSTDIN=0x%I64x STDOUT=0x%I64x STDERR=0x%I64x",
g_prefix,
(long long)GetStdHandle(STD_INPUT_HANDLE),
(long long)GetStdHandle(STD_OUTPUT_HANDLE),
(long long)GetStdHandle(STD_ERROR_HANDLE));
}
static const char *successOrFail(BOOL ret) {
return ret ? "ok" : "FAILED";
}
static void startChildInSameConsole(const wchar_t *args, BOOL
bInheritHandles=FALSE) {
wchar_t program[1024];
wchar_t cmdline[1024];
GetModuleFileNameW(NULL, program, 1024);
swprintf(cmdline, L"\"%ls\" %ls", program, args);
STARTUPINFOW sui;
PROCESS_INFORMATION pi;
memset(&sui, 0, sizeof(sui));
memset(&pi, 0, sizeof(pi));
sui.cb = sizeof(sui);
CreateProcessW(program, cmdline,
NULL, NULL,
/*bInheritHandles=*/bInheritHandles,
/*dwCreationFlags=*/0,
NULL, NULL,
&sui, &pi);
}
static void closeHandle(HANDLE h) {
trace("%sClosing handle 0x%I64x...", g_prefix, (long long)h);
trace("%sClosing handle 0x%I64x... %s", g_prefix, (long long)h, successOrFail(CloseHandle(h)));
}
static HANDLE createBuffer() {
// If sa isn't provided, the handle defaults to not-inheritable.
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
trace("%sCreating a new buffer...", g_prefix);
HANDLE conout = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
CONSOLE_TEXTMODE_BUFFER, NULL);
trace("%sCreating a new buffer... 0x%I64x", g_prefix, (long long)conout);
return conout;
}
static HANDLE openConout() {
// If sa isn't provided, the handle defaults to not-inheritable.
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
trace("%sOpening CONOUT...", g_prefix);
HANDLE conout = CreateFileW(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING, 0, NULL);
trace("%sOpening CONOUT... 0x%I64x", g_prefix, (long long)conout);
return conout;
}
static void setConsoleActiveScreenBuffer(HANDLE conout) {
trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called...",
g_prefix, (long long)conout);
trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called... %s",
g_prefix, (long long)conout,
successOrFail(SetConsoleActiveScreenBuffer(conout)));
}
static void writeTest(HANDLE conout, const char *msg) {
char writeData[256];
sprintf(writeData, "%s%s\n", g_prefix, msg);
trace("%sWriting to 0x%I64x: '%s'...",
g_prefix, (long long)conout, msg);
DWORD actual = 0;
BOOL ret = WriteConsoleA(conout, writeData, strlen(writeData), &actual, NULL);
trace("%sWriting to 0x%I64x: '%s'... %s",
g_prefix, (long long)conout, msg,
successOrFail(ret && actual == strlen(writeData)));
}
static void writeTest(const char *msg) {
writeTest(GetStdHandle(STD_OUTPUT_HANDLE), msg);
}
///////////////////////////////////////////////////////////////////////////////
// TEST 1 -- create new buffer, activate it, and close the handle. The console
// automatically switches the screen buffer back to the original.
//
// This test passes everywhere.
//
static void test1(int argc, char *argv[]) {
if (!strcmp(argv[1], "1")) {
startChildProcess(L"1:child");
return;
}
HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
writeTest(origBuffer, "<-- origBuffer -->");
HANDLE newBuffer = createBuffer();
writeTest(newBuffer, "<-- newBuffer -->");
setConsoleActiveScreenBuffer(newBuffer);
Sleep(2000);
writeTest(origBuffer, "TEST PASSED!");
// Closing the handle w/o switching the active screen buffer automatically
// switches the console back to the original buffer.
closeHandle(newBuffer);
while (true) {
Sleep(1000);
}
}
///////////////////////////////////////////////////////////////////////////////
// TEST 2 -- Test program that creates and activates newBuffer, starts a child
// process, then closes its newBuffer handle. newBuffer remains activated,
// because the child keeps it active. (Also see TEST D.)
//
static void test2(int argc, char *argv[]) {
if (!strcmp(argv[1], "2")) {
startChildProcess(L"2:parent");
return;
}
if (!strcmp(argv[1], "2:parent")) {
g_prefix = "parent: ";
dumpHandles();
HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
writeTest(origBuffer, "<-- origBuffer -->");
HANDLE newBuffer = createBuffer();
writeTest(newBuffer, "<-- newBuffer -->");
setConsoleActiveScreenBuffer(newBuffer);
Sleep(1000);
writeTest(newBuffer, "bInheritHandles=FALSE:");
startChildInSameConsole(L"2:child", FALSE);
Sleep(1000);
writeTest(newBuffer, "bInheritHandles=TRUE:");
startChildInSameConsole(L"2:child", TRUE);
Sleep(1000);
trace("parent:----");
// Close the new buffer. The active screen buffer doesn't automatically
// switch back to origBuffer, because the child process has a handle open
// to the original buffer.
closeHandle(newBuffer);
Sleep(600 * 1000);
return;
}
if (!strcmp(argv[1], "2:child")) {
g_prefix = "child: ";
dumpHandles();
// The child's output isn't visible, because it's still writing to
// origBuffer.
trace("child:----");
writeTest("writing to STDOUT");
// Handle inheritability is curious. The console handles this program
// creates are inheritable, but CreateProcess is called with both
// bInheritHandles=TRUE and bInheritHandles=FALSE.
//
// Vista and Windows 7: bInheritHandles has no effect. The child and
// parent processes have the same STDIN/STDOUT/STDERR handles:
// 0x3, 0x7, and 0xB. The parent has a 0xF handle for newBuffer.
// The child can only write to 0x7, 0xB, and 0xF. Only the writes to
// 0xF are visible (i.e. they touch newBuffer).
//
// Windows 8 or Windows 10 (legacy or non-legacy): the lowest 2 bits of
// the HANDLE to WriteConsole seem to be ignored. The new process'
// console handles always refer to the buffer that was active when they
// started, but the values of the handles depend upon bInheritHandles.
// With bInheritHandles=TRUE, the child has the same
// STDIN/STDOUT/STDERR/newBuffer handles as the parent, and the three
// output handles all work, though their output is all visible. With
// bInheritHandles=FALSE, the child has different STDIN/STDOUT/STDERR
// handles, and only the new STDOUT/STDERR handles work.
//
for (unsigned int i = 0x1; i <= 0xB0; ++i) {
char msg[256];
sprintf(msg, "Write to handle 0x%x", i);
HANDLE h = reinterpret_cast<HANDLE>(i);
writeTest(h, msg);
}
Sleep(600 * 1000);
return;
}
}
///////////////////////////////////////////////////////////////////////////////
// TEST A -- demonstrate an apparent Windows bug with screen buffers
//
// Steps:
// - The parent starts a child process.
// - The child process creates and activates newBuffer
// - The parent opens CONOUT$ and writes to it.
// - The parent closes CONOUT$.
// - At this point, broken Windows reactivates origBuffer.
// - The child writes to newBuffer again.
// - The child activates origBuffer again, then closes newBuffer.
//
// Test passes if the message "TEST PASSED!" is visible.
// Test commonly fails if conhost.exe crashes.
//
// Results:
// - Windows 7 Ultimate SP1 32-bit: conhost.exe crashes
// - Windows Server 2008 R2 Datacenter SP1 64-bit: PASS
// - Windows 8 Enterprise 32-bit: PASS
// - Windows 10 64-bit (legacy and non-legacy): PASS
//
static void testA_parentWork() {
// Open an extra CONOUT$ handle so that the HANDLE values in parent and
// child don't collide. I think it's OK if they collide, but since we're
// trying to track down a Windows bug, it's best to avoid unnecessary
// complication.
HANDLE dummy = openConout();
Sleep(3000);
// Step 2: Open CONOUT$ in the parent. This opens the active buffer, which
// was just created in the child. It's handle 0x13. Write to it.
HANDLE newBuffer = openConout();
writeTest(newBuffer, "step2: writing to newBuffer");
Sleep(3000);
// Step 3: Close handle 0x13. With Windows 7, the console switches back to
// origBuffer, and (unless I'm missing something) it shouldn't.
closeHandle(newBuffer);
}
static void testA_childWork() {
HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
//
// Step 1: Create the new screen buffer in the child process and make it
// active. (Typically, it's handle 0x0F.)
//
HANDLE newBuffer = createBuffer();
setConsoleActiveScreenBuffer(newBuffer);
writeTest(newBuffer, "<-- newBuffer -->");
Sleep(9000);
trace("child:----");
// Step 4: write to the newBuffer again.
writeTest(newBuffer, "TEST PASSED!");
//
// Step 5: Switch back to the original screen buffer and close the new
// buffer. The switch call succeeds, but the CloseHandle call freezes for
// several seconds, because conhost.exe crashes.
//
Sleep(3000);
setConsoleActiveScreenBuffer(origBuffer);
writeTest(origBuffer, "writing to origBuffer");
closeHandle(newBuffer);
// The console HWND is NULL.
trace("child: console HWND=0x%I64x", (long long)GetConsoleWindow());
// At this point, the console window has closed, but the parent/child
// processes are still running. Calling AllocConsole would fail, but
// calling FreeConsole followed by AllocConsole would both succeed, and a
// new console would appear.
}
static void testA(int argc, char *argv[]) {
if (!strcmp(argv[1], "A")) {
startChildProcess(L"A:parent");
return;
}
if (!strcmp(argv[1], "A:parent")) {
g_prefix = "parent: ";
trace("parent:----");
dumpHandles();
writeTest("<-- origBuffer -->");
startChildInSameConsole(L"A:child");
testA_parentWork();
Sleep(120000);
return;
}
if (!strcmp(argv[1], "A:child")) {
g_prefix = "child: ";
dumpHandles();
testA_childWork();
Sleep(120000);
return;
}
}
///////////////////////////////////////////////////////////////////////////////
// TEST B -- invert TEST A -- also crashes conhost on Windows 7
//
// Test passes if the message "TEST PASSED!" is visible.
// Test commonly fails if conhost.exe crashes.
//
// Results:
// - Windows 7 Ultimate SP1 32-bit: conhost.exe crashes
// - Windows Server 2008 R2 Datacenter SP1 64-bit: PASS
// - Windows 8 Enterprise 32-bit: PASS
// - Windows 10 64-bit (legacy and non-legacy): PASS
//
static void testB(int argc, char *argv[]) {
if (!strcmp(argv[1], "B")) {
startChildProcess(L"B:parent");
return;
}
if (!strcmp(argv[1], "B:parent")) {
g_prefix = "parent: ";
startChildInSameConsole(L"B:child");
writeTest("<-- origBuffer -->");
HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
//
// Step 1: Create the new buffer and make it active.
//
trace("%s----", g_prefix);
HANDLE newBuffer = createBuffer();
setConsoleActiveScreenBuffer(newBuffer);
writeTest(newBuffer, "<-- newBuffer -->");
//
// Step 4: Attempt to write again to the new buffer.
//
Sleep(9000);
trace("%s----", g_prefix);
writeTest(newBuffer, "TEST PASSED!");
//
// Step 5: Switch back to the original buffer.
//
Sleep(3000);
trace("%s----", g_prefix);
setConsoleActiveScreenBuffer(origBuffer);
closeHandle(newBuffer);
writeTest(origBuffer, "writing to the initial buffer");
Sleep(60000);
return;
}
if (!strcmp(argv[1], "B:child")) {
g_prefix = "child: ";
Sleep(3000);
trace("%s----", g_prefix);
//
// Step 2: Open the newly active buffer and write to it.
//
HANDLE newBuffer = openConout();
writeTest(newBuffer, "writing to newBuffer");
//
// Step 3: Close the newly active buffer.
//
Sleep(3000);
closeHandle(newBuffer);
Sleep(60000);
return;
}
}
///////////////////////////////////////////////////////////////////////////////
// TEST C -- Interleaving open/close of console handles also seems to break on
// Windows 7.
//
// Test:
// - child creates and activates newBuf1
// - parent opens newBuf1
// - child creates and activates newBuf2
// - parent opens newBuf2, then closes newBuf1
// - child switches back to newBuf1
// * At this point, the console starts malfunctioning.
// - parent and child close newBuf2
// - child closes newBuf1
//
// Test passes if the message "TEST PASSED!" is visible.
// Test commonly fails if conhost.exe crashes.
//
// Results:
// - Windows 7 Ultimate SP1 32-bit: conhost.exe crashes
// - Windows Server 2008 R2 Datacenter SP1 64-bit: PASS
// - Windows 8 Enterprise 32-bit: PASS
// - Windows 10 64-bit (legacy and non-legacy): PASS
//
static void testC(int argc, char *argv[]) {
if (!strcmp(argv[1], "C")) {
startChildProcess(L"C:parent");
return;
}
if (!strcmp(argv[1], "C:parent")) {
startChildInSameConsole(L"C:child");
writeTest("<-- origBuffer -->");
g_prefix = "parent: ";
// At time=4, open newBuffer1.
Sleep(4000);
trace("%s---- t=4", g_prefix);
const HANDLE newBuffer1 = openConout();
// At time=8, open newBuffer2, and close newBuffer1.
Sleep(4000);
trace("%s---- t=8", g_prefix);
const HANDLE newBuffer2 = openConout();
closeHandle(newBuffer1);
// At time=25, cleanup of newBuffer2.
Sleep(17000);
trace("%s---- t=25", g_prefix);
closeHandle(newBuffer2);
Sleep(240000);
return;
}
if (!strcmp(argv[1], "C:child")) {
g_prefix = "child: ";
// At time=2, create newBuffer1 and activate it.
Sleep(2000);
trace("%s---- t=2", g_prefix);
const HANDLE newBuffer1 = createBuffer();
setConsoleActiveScreenBuffer(newBuffer1);
writeTest(newBuffer1, "<-- newBuffer1 -->");
// At time=6, create newBuffer2 and activate it.
Sleep(4000);
trace("%s---- t=6", g_prefix);
const HANDLE newBuffer2 = createBuffer();
setConsoleActiveScreenBuffer(newBuffer2);
writeTest(newBuffer2, "<-- newBuffer2 -->");
// At time=10, attempt to switch back to newBuffer1. The parent process
// has opened and closed its handle to newBuffer1, so does it still exist?
Sleep(4000);
trace("%s---- t=10", g_prefix);
setConsoleActiveScreenBuffer(newBuffer1);
writeTest(newBuffer1, "write to newBuffer1: TEST PASSED!");
// At time=25, cleanup of newBuffer2.
Sleep(15000);
trace("%s---- t=25", g_prefix);
closeHandle(newBuffer2);
// At time=35, cleanup of newBuffer1. The console should switch to the
// initial buffer again.
Sleep(10000);
trace("%s---- t=35", g_prefix);
closeHandle(newBuffer1);
Sleep(240000);
return;
}
}
///////////////////////////////////////////////////////////////////////////////
// TEST D -- parent creates a new buffer, child launches, writes,
// closes it output handle, then parent writes again. (Also see TEST 2.)
//
// On success, this will appear:
//
// parent: <-- newBuffer -->
// child: writing to newBuffer
// parent: TEST PASSED!
//
// If this appears, it indicates that the child's closing its output handle did
// not destroy newBuffer.
//
// Results:
// - Windows 7 Ultimate SP1 32-bit: PASS
// - Windows 8 Enterprise 32-bit: PASS
// - Windows 10 64-bit (legacy and non-legacy): PASS
//
static void testD(int argc, char *argv[]) {
if (!strcmp(argv[1], "D")) {
startChildProcess(L"D:parent");
return;
}
if (!strcmp(argv[1], "D:parent")) {
g_prefix = "parent: ";
HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE);
writeTest(origBuffer, "<-- origBuffer -->");
HANDLE newBuffer = createBuffer();
writeTest(newBuffer, "<-- newBuffer -->");
setConsoleActiveScreenBuffer(newBuffer);
// At t=2, start a child process, explicitly forcing it to use
// newBuffer for its standard handles. These calls are apparently
// redundant on Windows 8 and up.
Sleep(2000);
trace("parent:----");
trace("parent: starting child process");
SetStdHandle(STD_OUTPUT_HANDLE, newBuffer);
SetStdHandle(STD_ERROR_HANDLE, newBuffer);
startChildInSameConsole(L"D:child");
SetStdHandle(STD_OUTPUT_HANDLE, origBuffer);
SetStdHandle(STD_ERROR_HANDLE, origBuffer);
// At t=6, write again to newBuffer.
Sleep(4000);
trace("parent:----");
writeTest(newBuffer, "TEST PASSED!");
// At t=8, close the newBuffer. In earlier versions of windows
// (including Server 2008 R2), the console then switches back to
// origBuffer. As of Windows 8, it doesn't, because somehow the child
// process is keeping the console on newBuffer, even though the child
// process closed its STDIN/STDOUT/STDERR handles. Killing the child
// process by hand after the test finishes *does* force the console
// back to origBuffer.
Sleep(2000);
closeHandle(newBuffer);
Sleep(120000);
return;
}
if (!strcmp(argv[1], "D:child")) {
g_prefix = "child: ";
// At t=2, the child starts.
trace("child:----");
dumpHandles();
writeTest("writing to newBuffer");
// At t=4, the child explicitly closes its handle.
Sleep(2000);
trace("child:----");
if (GetStdHandle(STD_ERROR_HANDLE) != GetStdHandle(STD_OUTPUT_HANDLE)) {
closeHandle(GetStdHandle(STD_ERROR_HANDLE));
}
closeHandle(GetStdHandle(STD_OUTPUT_HANDLE));
closeHandle(GetStdHandle(STD_INPUT_HANDLE));
Sleep(120000);
return;
}
}
int main(int argc, char *argv[]) {
if (argc == 1) {
printf("USAGE: %s testnum\n", argv[0]);
return 0;
}
if (argv[1][0] == '1') {
test1(argc, argv);
} else if (argv[1][0] == '2') {
test2(argc, argv);
} else if (argv[1][0] == 'A') {
testA(argc, argv);
} else if (argv[1][0] == 'B') {
testB(argc, argv);
} else if (argv[1][0] == 'C') {
testC(argc, argv);
} else if (argv[1][0] == 'D') {
testD(argc, argv);
}
return 0;
}

View File

@@ -0,0 +1,151 @@
#include <windows.h>
#include "TestUtil.cc"
const char *g_prefix = "";
static void dumpHandles() {
trace("%sSTDIN=0x%I64x STDOUT=0x%I64x STDERR=0x%I64x",
g_prefix,
(long long)GetStdHandle(STD_INPUT_HANDLE),
(long long)GetStdHandle(STD_OUTPUT_HANDLE),
(long long)GetStdHandle(STD_ERROR_HANDLE));
}
static HANDLE createBuffer() {
// If sa isn't provided, the handle defaults to not-inheritable.
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
trace("%sCreating a new buffer...", g_prefix);
HANDLE conout = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
CONSOLE_TEXTMODE_BUFFER, NULL);
trace("%sCreating a new buffer... 0x%I64x", g_prefix, (long long)conout);
return conout;
}
static const char *successOrFail(BOOL ret) {
return ret ? "ok" : "FAILED";
}
static void setConsoleActiveScreenBuffer(HANDLE conout) {
trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called...",
g_prefix, (long long)conout);
trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called... %s",
g_prefix, (long long)conout,
successOrFail(SetConsoleActiveScreenBuffer(conout)));
}
static void writeTest(HANDLE conout, const char *msg) {
char writeData[256];
sprintf(writeData, "%s%s\n", g_prefix, msg);
trace("%sWriting to 0x%I64x: '%s'...",
g_prefix, (long long)conout, msg);
DWORD actual = 0;
BOOL ret = WriteConsoleA(conout, writeData, strlen(writeData), &actual, NULL);
trace("%sWriting to 0x%I64x: '%s'... %s",
g_prefix, (long long)conout, msg,
successOrFail(ret && actual == strlen(writeData)));
}
static HANDLE startChildInSameConsole(const wchar_t *args, BOOL
bInheritHandles=FALSE) {
wchar_t program[1024];
wchar_t cmdline[1024];
GetModuleFileNameW(NULL, program, 1024);
swprintf(cmdline, L"\"%ls\" %ls", program, args);
STARTUPINFOW sui;
PROCESS_INFORMATION pi;
memset(&sui, 0, sizeof(sui));
memset(&pi, 0, sizeof(pi));
sui.cb = sizeof(sui);
CreateProcessW(program, cmdline,
NULL, NULL,
/*bInheritHandles=*/bInheritHandles,
/*dwCreationFlags=*/0,
NULL, NULL,
&sui, &pi);
return pi.hProcess;
}
static HANDLE dup(HANDLE h, HANDLE targetProcess) {
HANDLE h2 = INVALID_HANDLE_VALUE;
BOOL ret = DuplicateHandle(
GetCurrentProcess(), h,
targetProcess, &h2,
0, TRUE, DUPLICATE_SAME_ACCESS);
trace("dup(0x%I64x) to process 0x%I64x... %s, 0x%I64x",
(long long)h,
(long long)targetProcess,
successOrFail(ret),
(long long)h2);
return h2;
}
int main(int argc, char *argv[]) {
if (argc == 1) {
startChildProcess(L"parent");
return 0;
}
if (!strcmp(argv[1], "parent")) {
g_prefix = "parent: ";
dumpHandles();
HANDLE hChild = startChildInSameConsole(L"child");
// Windows 10.
HANDLE orig1 = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE new1 = createBuffer();
Sleep(2000);
setConsoleActiveScreenBuffer(new1);
// Handle duplication results to child process in same console:
// - Windows XP: fails
// - Windows 7 Ultimate SP1 32-bit: fails
// - Windows Server 2008 R2 Datacenter SP1 64-bit: fails
// - Windows 8 Enterprise 32-bit: succeeds
// - Windows 10: succeeds
HANDLE orig2 = dup(orig1, GetCurrentProcess());
HANDLE new2 = dup(new1, GetCurrentProcess());
dup(orig1, hChild);
dup(new1, hChild);
// The writes to orig1/orig2 are invisible. The writes to new1/new2
// are visible.
writeTest(orig1, "write to orig1");
writeTest(orig2, "write to orig2");
writeTest(new1, "write to new1");
writeTest(new2, "write to new2");
Sleep(120000);
return 0;
}
if (!strcmp(argv[1], "child")) {
g_prefix = "child: ";
dumpHandles();
Sleep(4000);
for (unsigned int i = 0x1; i <= 0xB0; ++i) {
char msg[256];
sprintf(msg, "Write to handle 0x%x", i);
HANDLE h = reinterpret_cast<HANDLE>(i);
writeTest(h, msg);
}
Sleep(120000);
return 0;
}
return 0;
}

View File

@@ -0,0 +1,45 @@
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <windows.h>
#include "../src/shared/DebugClient.cc"
const int SC_CONSOLE_MARK = 0xFFF2;
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
CALLBACK DWORD pausingThread(LPVOID dummy)
{
HWND hwnd = GetConsoleWindow();
while (true) {
SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0);
Sleep(1000);
SendMessage(hwnd, WM_CHAR, 27, 0x00010001);
Sleep(1000);
}
}
int main()
{
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(out, &info);
COORD initial = info.dwCursorPosition;
CreateThread(NULL, 0,
pausingThread, NULL,
0, NULL);
for (int i = 0; i < 30; ++i) {
Sleep(100);
GetConsoleScreenBufferInfo(out, &info);
if (memcmp(&info.dwCursorPosition, &initial, sizeof(COORD)) != 0) {
trace("cursor moved to [%d,%d]",
info.dwCursorPosition.X,
info.dwCursorPosition.Y);
} else {
trace("cursor in expected position");
}
}
return 0;
}

View File

@@ -0,0 +1,90 @@
#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "TestUtil.cc"
static void usage() {
printf("usage: SetBufInfo [-set] [-buf W H] [-win W H] [-pos X Y]\n");
}
int main(int argc, char *argv[]) {
const HANDLE conout = CreateFileW(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
ASSERT(conout != INVALID_HANDLE_VALUE);
bool change = false;
BOOL success;
CONSOLE_SCREEN_BUFFER_INFOEX info = {};
info.cbSize = sizeof(info);
success = GetConsoleScreenBufferInfoEx(conout, &info);
ASSERT(success && "GetConsoleScreenBufferInfoEx failed");
for (int i = 1; i < argc; ) {
std::string arg = argv[i];
if (arg == "-buf" && (i + 2) < argc) {
info.dwSize.X = atoi(argv[i + 1]);
info.dwSize.Y = atoi(argv[i + 2]);
i += 3;
change = true;
} else if (arg == "-pos" && (i + 2) < argc) {
int dx = info.srWindow.Right - info.srWindow.Left;
int dy = info.srWindow.Bottom - info.srWindow.Top;
info.srWindow.Left = atoi(argv[i + 1]);
info.srWindow.Top = atoi(argv[i + 2]);
i += 3;
info.srWindow.Right = info.srWindow.Left + dx;
info.srWindow.Bottom = info.srWindow.Top + dy;
change = true;
} else if (arg == "-win" && (i + 2) < argc) {
info.srWindow.Right = info.srWindow.Left + atoi(argv[i + 1]) - 1;
info.srWindow.Bottom = info.srWindow.Top + atoi(argv[i + 2]) - 1;
i += 3;
change = true;
} else if (arg == "-set") {
change = true;
++i;
} else if (arg == "--help" || arg == "-help") {
usage();
exit(0);
} else {
fprintf(stderr, "error: unrecognized argument: %s\n", arg.c_str());
usage();
exit(1);
}
}
if (change) {
success = SetConsoleScreenBufferInfoEx(conout, &info);
if (success) {
printf("success\n");
} else {
printf("SetConsoleScreenBufferInfoEx call failed\n");
}
success = GetConsoleScreenBufferInfoEx(conout, &info);
ASSERT(success && "GetConsoleScreenBufferInfoEx failed");
}
auto dump = [](const char *fmt, ...) {
char msg[256];
va_list ap;
va_start(ap, fmt);
vsprintf(msg, fmt, ap);
va_end(ap);
trace("%s", msg);
printf("%s\n", msg);
};
dump("buffer-size: %d x %d", info.dwSize.X, info.dwSize.Y);
dump("window-size: %d x %d",
info.srWindow.Right - info.srWindow.Left + 1,
info.srWindow.Bottom - info.srWindow.Top + 1);
dump("window-pos: %d, %d", info.srWindow.Left, info.srWindow.Top);
return 0;
}

View File

@@ -0,0 +1,32 @@
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "TestUtil.cc"
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: %s x y width height\n", argv[0]);
return 1;
}
const HANDLE conout = CreateFileW(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
ASSERT(conout != INVALID_HANDLE_VALUE);
COORD size = {
(short)atoi(argv[1]),
(short)atoi(argv[2]),
};
BOOL ret = SetConsoleScreenBufferSize(conout, size);
const unsigned lastError = GetLastError();
const char *const retStr = ret ? "OK" : "failed";
trace("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)", retStr, lastError);
printf("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)\n", retStr, lastError);
return 0;
}

View File

@@ -0,0 +1,10 @@
#include <windows.h>
#include "TestUtil.cc"
int main(int argc, char *argv[]) {
int col = atoi(argv[1]);
int row = atoi(argv[2]);
setCursorPos(col, row);
return 0;
}

145
src/libs/3rdparty/winpty/misc/SetFont.cc vendored Normal file
View File

@@ -0,0 +1,145 @@
#include <windows.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "TestUtil.cc"
#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0]))
// See https://en.wikipedia.org/wiki/List_of_CJK_fonts
const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese
const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese
const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese
const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean
int main() {
setlocale(LC_ALL, "");
wchar_t *cmdline = GetCommandLineW();
int argc = 0;
wchar_t **argv = CommandLineToArgvW(cmdline, &argc);
const HANDLE conout = openConout();
if (argc == 1) {
cprintf(L"Usage:\n");
cprintf(L" SetFont <index>\n");
cprintf(L" SetFont options\n");
cprintf(L"\n");
cprintf(L"Options for SetCurrentConsoleFontEx:\n");
cprintf(L" -idx INDEX\n");
cprintf(L" -w WIDTH\n");
cprintf(L" -h HEIGHT\n");
cprintf(L" -family (0xNN|NN)\n");
cprintf(L" -weight (normal|bold|NNN)\n");
cprintf(L" -face FACENAME\n");
cprintf(L" -face-{gothic|simsun|minglight|gulimche) [JP,CN-sim,CN-tra,KR]\n");
cprintf(L" -tt\n");
cprintf(L" -vec\n");
cprintf(L" -vp\n");
cprintf(L" -dev\n");
cprintf(L" -roman\n");
cprintf(L" -swiss\n");
cprintf(L" -modern\n");
cprintf(L" -script\n");
cprintf(L" -decorative\n");
return 0;
}
if (isdigit(argv[1][0])) {
int index = _wtoi(argv[1]);
HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
FARPROC proc = GetProcAddress(kernel32, "SetConsoleFont");
if (proc == NULL) {
cprintf(L"Couldn't get address of SetConsoleFont\n");
} else {
BOOL ret = reinterpret_cast<BOOL WINAPI(*)(HANDLE, DWORD)>(proc)(
conout, index);
cprintf(L"SetFont returned %d\n", ret);
}
return 0;
}
CONSOLE_FONT_INFOEX fontex = {0};
fontex.cbSize = sizeof(fontex);
for (int i = 1; i < argc; ++i) {
std::wstring arg = argv[i];
if (i + 1 < argc) {
std::wstring next = argv[i + 1];
if (arg == L"-idx") {
fontex.nFont = _wtoi(next.c_str());
++i; continue;
} else if (arg == L"-w") {
fontex.dwFontSize.X = _wtoi(next.c_str());
++i; continue;
} else if (arg == L"-h") {
fontex.dwFontSize.Y = _wtoi(next.c_str());
++i; continue;
} else if (arg == L"-weight") {
if (next == L"normal") {
fontex.FontWeight = 400;
} else if (next == L"bold") {
fontex.FontWeight = 700;
} else {
fontex.FontWeight = _wtoi(next.c_str());
}
++i; continue;
} else if (arg == L"-face") {
wcsncpy(fontex.FaceName, next.c_str(), COUNT_OF(fontex.FaceName));
++i; continue;
} else if (arg == L"-family") {
fontex.FontFamily = strtol(narrowString(next).c_str(), nullptr, 0);
++i; continue;
}
}
if (arg == L"-tt") {
fontex.FontFamily |= TMPF_TRUETYPE;
} else if (arg == L"-vec") {
fontex.FontFamily |= TMPF_VECTOR;
} else if (arg == L"-vp") {
// Setting the TMPF_FIXED_PITCH bit actually indicates variable
// pitch.
fontex.FontFamily |= TMPF_FIXED_PITCH;
} else if (arg == L"-dev") {
fontex.FontFamily |= TMPF_DEVICE;
} else if (arg == L"-roman") {
fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_ROMAN;
} else if (arg == L"-swiss") {
fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_SWISS;
} else if (arg == L"-modern") {
fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_MODERN;
} else if (arg == L"-script") {
fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_SCRIPT;
} else if (arg == L"-decorative") {
fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_DECORATIVE;
} else if (arg == L"-face-gothic") {
wcsncpy(fontex.FaceName, kMSGothic, COUNT_OF(fontex.FaceName));
} else if (arg == L"-face-simsun") {
wcsncpy(fontex.FaceName, kNSimSun, COUNT_OF(fontex.FaceName));
} else if (arg == L"-face-minglight") {
wcsncpy(fontex.FaceName, kMingLight, COUNT_OF(fontex.FaceName));
} else if (arg == L"-face-gulimche") {
wcsncpy(fontex.FaceName, kGulimChe, COUNT_OF(fontex.FaceName));
} else {
cprintf(L"Unrecognized argument: %ls\n", arg.c_str());
exit(1);
}
}
cprintf(L"Setting to: nFont=%u dwFontSize=(%d,%d) "
L"FontFamily=0x%x FontWeight=%u "
L"FaceName=\"%ls\"\n",
static_cast<unsigned>(fontex.nFont),
fontex.dwFontSize.X, fontex.dwFontSize.Y,
fontex.FontFamily, fontex.FontWeight,
fontex.FaceName);
BOOL ret = SetCurrentConsoleFontEx(
conout,
FALSE,
&fontex);
cprintf(L"SetCurrentConsoleFontEx returned %d\n", ret);
return 0;
}

View File

@@ -0,0 +1,36 @@
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "TestUtil.cc"
int main(int argc, char *argv[]) {
if (argc != 5) {
printf("Usage: %s x y width height\n", argv[0]);
return 1;
}
const HANDLE conout = CreateFileW(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
ASSERT(conout != INVALID_HANDLE_VALUE);
SMALL_RECT sr = {
(short)atoi(argv[1]),
(short)atoi(argv[2]),
(short)(atoi(argv[1]) + atoi(argv[3]) - 1),
(short)(atoi(argv[2]) + atoi(argv[4]) - 1),
};
trace("Calling SetConsoleWindowInfo with {L=%d,T=%d,R=%d,B=%d}",
sr.Left, sr.Top, sr.Right, sr.Bottom);
BOOL ret = SetConsoleWindowInfo(conout, TRUE, &sr);
const unsigned lastError = GetLastError();
const char *const retStr = ret ? "OK" : "failed";
trace("SetConsoleWindowInfo ret: %s (LastError=0x%x)", retStr, lastError);
printf("SetConsoleWindowInfo ret: %s (LastError=0x%x)\n", retStr, lastError);
return 0;
}

View File

@@ -0,0 +1,12 @@
// This test program is useful for studying commandline<->argv conversion.
#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv)
{
printf("cmdline = [%s]\n", GetCommandLine());
for (int i = 0; i < argc; ++i)
printf("[%s]\n", argv[i]);
return 0;
}

View File

@@ -0,0 +1,40 @@
#include <windows.h>
#include <stdio.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
static int escCount = 0;
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
while (true) {
DWORD count;
INPUT_RECORD ir;
if (!ReadConsoleInput(hStdin, &ir, 1, &count)) {
printf("ReadConsoleInput failed\n");
return 1;
}
if (true) {
DWORD mode;
GetConsoleMode(hStdin, &mode);
SetConsoleMode(hStdin, mode & ~ENABLE_PROCESSED_INPUT);
}
if (ir.EventType == KEY_EVENT) {
const KEY_EVENT_RECORD &ker = ir.Event.KeyEvent;
printf("%s", ker.bKeyDown ? "dn" : "up");
printf(" ch=");
if (isprint(ker.uChar.AsciiChar))
printf("'%c'", ker.uChar.AsciiChar);
printf("%d", ker.uChar.AsciiChar);
printf(" vk=%#x", ker.wVirtualKeyCode);
printf(" scan=%#x", ker.wVirtualScanCode);
printf(" state=%#x", (int)ker.dwControlKeyState);
printf(" repeat=%d", ker.wRepeatCount);
printf("\n");
if (ker.uChar.AsciiChar == 27 && ++escCount == 6)
break;
}
}
}

5
src/libs/3rdparty/winpty/misc/Spew.py vendored Normal file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env python
i = 0;
while True:
i += 1
print(i)

View File

@@ -0,0 +1,172 @@
// This file is included into test programs using #include
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <vector>
#include <string>
#include "../src/shared/DebugClient.h"
#include "../src/shared/TimeMeasurement.h"
#include "../src/shared/DebugClient.cc"
#include "../src/shared/WinptyAssert.cc"
#include "../src/shared/WinptyException.cc"
// Launch this test program again, in a new console that we will destroy.
static void startChildProcess(const wchar_t *args) {
wchar_t program[1024];
wchar_t cmdline[1024];
GetModuleFileNameW(NULL, program, 1024);
swprintf(cmdline, L"\"%ls\" %ls", program, args);
STARTUPINFOW sui;
PROCESS_INFORMATION pi;
memset(&sui, 0, sizeof(sui));
memset(&pi, 0, sizeof(pi));
sui.cb = sizeof(sui);
CreateProcessW(program, cmdline,
NULL, NULL,
/*bInheritHandles=*/FALSE,
/*dwCreationFlags=*/CREATE_NEW_CONSOLE,
NULL, NULL,
&sui, &pi);
}
static void setBufferSize(HANDLE conout, int x, int y) {
COORD size = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
BOOL success = SetConsoleScreenBufferSize(conout, size);
trace("setBufferSize: (%d,%d), result=%d", x, y, success);
}
static void setWindowPos(HANDLE conout, int x, int y, int w, int h) {
SMALL_RECT r = {
static_cast<SHORT>(x), static_cast<SHORT>(y),
static_cast<SHORT>(x + w - 1),
static_cast<SHORT>(y + h - 1)
};
BOOL success = SetConsoleWindowInfo(conout, /*bAbsolute=*/TRUE, &r);
trace("setWindowPos: (%d,%d,%d,%d), result=%d", x, y, w, h, success);
}
static void setCursorPos(HANDLE conout, int x, int y) {
COORD coord = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
SetConsoleCursorPosition(conout, coord);
}
static void setBufferSize(int x, int y) {
setBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), x, y);
}
static void setWindowPos(int x, int y, int w, int h) {
setWindowPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y, w, h);
}
static void setCursorPos(int x, int y) {
setCursorPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y);
}
static void countDown(int sec) {
for (int i = sec; i > 0; --i) {
printf("%d.. ", i);
fflush(stdout);
Sleep(1000);
}
printf("\n");
}
static void writeBox(int x, int y, int w, int h, char ch, int attributes=7) {
CHAR_INFO info = { 0 };
info.Char.AsciiChar = ch;
info.Attributes = attributes;
std::vector<CHAR_INFO> buf(w * h, info);
HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
COORD bufSize = { static_cast<SHORT>(w), static_cast<SHORT>(h) };
COORD bufCoord = { 0, 0 };
SMALL_RECT writeRegion = {
static_cast<SHORT>(x),
static_cast<SHORT>(y),
static_cast<SHORT>(x + w - 1),
static_cast<SHORT>(y + h - 1)
};
WriteConsoleOutputA(conout, buf.data(), bufSize, bufCoord, &writeRegion);
}
static void setChar(int x, int y, char ch, int attributes=7) {
writeBox(x, y, 1, 1, ch, attributes);
}
static void fillChar(int x, int y, int repeat, char ch) {
COORD coord = { static_cast<SHORT>(x), static_cast<SHORT>(y) };
DWORD actual = 0;
FillConsoleOutputCharacterA(
GetStdHandle(STD_OUTPUT_HANDLE),
ch, repeat, coord, &actual);
}
static void repeatChar(int count, char ch) {
for (int i = 0; i < count; ++i) {
putchar(ch);
}
fflush(stdout);
}
// I don't know why, but wprintf fails to print this face name,
// " ゴシック" (aka MS Gothic). It helps to use wprintf instead of printf, and
// it helps to call `setlocale(LC_ALL, "")`, but the Japanese symbols are
// ultimately converted to `?` symbols, even though MS Gothic is able to
// display its own name, and the current code page is 932 (Shift-JIS).
static void cvfprintf(HANDLE conout, const wchar_t *fmt, va_list ap) {
wchar_t buffer[256];
vswprintf(buffer, 256 - 1, fmt, ap);
buffer[255] = L'\0';
DWORD actual = 0;
if (!WriteConsoleW(conout, buffer, wcslen(buffer), &actual, NULL)) {
wprintf(L"WriteConsoleW call failed!\n");
}
}
static void cfprintf(HANDLE conout, const wchar_t *fmt, ...) {
va_list ap;
va_start(ap, fmt);
cvfprintf(conout, fmt, ap);
va_end(ap);
}
static void cprintf(const wchar_t *fmt, ...) {
va_list ap;
va_start(ap, fmt);
cvfprintf(GetStdHandle(STD_OUTPUT_HANDLE), fmt, ap);
va_end(ap);
}
static std::string narrowString(const std::wstring &input)
{
int mblen = WideCharToMultiByte(
CP_UTF8, 0,
input.data(), input.size(),
NULL, 0, NULL, NULL);
if (mblen <= 0) {
return std::string();
}
std::vector<char> tmp(mblen);
int mblen2 = WideCharToMultiByte(
CP_UTF8, 0,
input.data(), input.size(),
tmp.data(), tmp.size(),
NULL, NULL);
assert(mblen2 == mblen);
return std::string(tmp.data(), tmp.size());
}
HANDLE openConout() {
const HANDLE conout = CreateFileW(L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
ASSERT(conout != INVALID_HANDLE_VALUE);
return conout;
}

View File

@@ -0,0 +1,102 @@
// Demonstrates how U+30FC is sometimes handled as a single-width character
// when it should be handled as a double-width character.
//
// It only runs on computers where 932 is a valid code page. Set the system
// local to "Japanese (Japan)" to ensure this.
//
// The problem seems to happen when U+30FC is printed in a console using the
// Lucida Console font, and only when that font is at certain sizes.
//
#include <windows.h>
#include <assert.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "TestUtil.cc"
#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
static void setFont(const wchar_t *faceName, int pxSize) {
CONSOLE_FONT_INFOEX infoex = {0};
infoex.cbSize = sizeof(infoex);
infoex.dwFontSize.Y = pxSize;
wcsncpy(infoex.FaceName, faceName, COUNT_OF(infoex.FaceName));
BOOL ret = SetCurrentConsoleFontEx(
GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &infoex);
assert(ret);
}
static bool performTest(const wchar_t testChar) {
const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(conout, 7);
system("cls");
DWORD actual = 0;
BOOL ret = WriteConsoleW(conout, &testChar, 1, &actual, NULL);
assert(ret && actual == 1);
CHAR_INFO verify[2];
COORD bufSize = {2, 1};
COORD bufCoord = {0, 0};
const SMALL_RECT readRegion = {0, 0, 1, 0};
SMALL_RECT actualRegion = readRegion;
ret = ReadConsoleOutputW(conout, verify, bufSize, bufCoord, &actualRegion);
assert(ret && !memcmp(&readRegion, &actualRegion, sizeof(readRegion)));
assert(verify[0].Char.UnicodeChar == testChar);
if (verify[1].Char.UnicodeChar == testChar) {
// Typical double-width behavior with a TrueType font. Pass.
assert(verify[0].Attributes == 0x107);
assert(verify[1].Attributes == 0x207);
return true;
} else if (verify[1].Char.UnicodeChar == 0) {
// Typical double-width behavior with a Raster Font. Pass.
assert(verify[0].Attributes == 7);
assert(verify[1].Attributes == 0);
return true;
} else if (verify[1].Char.UnicodeChar == L' ') {
// Single-width behavior. Fail.
assert(verify[0].Attributes == 7);
assert(verify[1].Attributes == 7);
return false;
} else {
// Unexpected output.
assert(false);
}
}
int main(int argc, char *argv[]) {
setlocale(LC_ALL, "");
if (argc == 1) {
startChildProcess(L"CHILD");
return 0;
}
assert(SetConsoleCP(932));
assert(SetConsoleOutputCP(932));
const wchar_t testChar = 0x30FC;
const wchar_t *const faceNames[] = {
L"Lucida Console",
L"Consolas",
L" ゴシック",
};
trace("Test started");
for (auto faceName : faceNames) {
for (int px = 1; px <= 50; ++px) {
setFont(faceName, px);
if (!performTest(testChar)) {
trace("FAILURE: %s %dpx", narrowString(faceName).c_str(), px);
}
}
}
trace("Test complete");
return 0;
}

View File

@@ -0,0 +1,246 @@
#include <windows.h>
#include <assert.h>
#include <vector>
#include "TestUtil.cc"
#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
CHAR_INFO ci(wchar_t ch, WORD attributes) {
CHAR_INFO ret;
ret.Char.UnicodeChar = ch;
ret.Attributes = attributes;
return ret;
}
CHAR_INFO ci(wchar_t ch) {
return ci(ch, 7);
}
CHAR_INFO ci() {
return ci(L' ');
}
bool operator==(SMALL_RECT x, SMALL_RECT y) {
return !memcmp(&x, &y, sizeof(x));
}
SMALL_RECT sr(COORD pt, COORD size) {
return {
pt.X, pt.Y,
static_cast<SHORT>(pt.X + size.X - 1),
static_cast<SHORT>(pt.Y + size.Y - 1)
};
}
static void set(
const COORD pt,
const COORD size,
const std::vector<CHAR_INFO> &data) {
assert(data.size() == size.X * size.Y);
SMALL_RECT writeRegion = sr(pt, size);
BOOL ret = WriteConsoleOutputW(
GetStdHandle(STD_OUTPUT_HANDLE),
data.data(), size, {0, 0}, &writeRegion);
assert(ret && writeRegion == sr(pt, size));
}
static void set(
const COORD pt,
const std::vector<CHAR_INFO> &data) {
set(pt, {static_cast<SHORT>(data.size()), 1}, data);
}
static void writeAttrsAt(
const COORD pt,
const std::vector<WORD> &data) {
DWORD actual = 0;
BOOL ret = WriteConsoleOutputAttribute(
GetStdHandle(STD_OUTPUT_HANDLE),
data.data(), data.size(), pt, &actual);
assert(ret && actual == data.size());
}
static void writeCharsAt(
const COORD pt,
const std::vector<wchar_t> &data) {
DWORD actual = 0;
BOOL ret = WriteConsoleOutputCharacterW(
GetStdHandle(STD_OUTPUT_HANDLE),
data.data(), data.size(), pt, &actual);
assert(ret && actual == data.size());
}
static void writeChars(
const std::vector<wchar_t> &data) {
DWORD actual = 0;
BOOL ret = WriteConsoleW(
GetStdHandle(STD_OUTPUT_HANDLE),
data.data(), data.size(), &actual, NULL);
assert(ret && actual == data.size());
}
std::vector<CHAR_INFO> get(
const COORD pt,
const COORD size) {
std::vector<CHAR_INFO> data(size.X * size.Y);
SMALL_RECT readRegion = sr(pt, size);
BOOL ret = ReadConsoleOutputW(
GetStdHandle(STD_OUTPUT_HANDLE),
data.data(), size, {0, 0}, &readRegion);
assert(ret && readRegion == sr(pt, size));
return data;
}
std::vector<wchar_t> readCharsAt(
const COORD pt,
int size) {
std::vector<wchar_t> data(size);
DWORD actual = 0;
BOOL ret = ReadConsoleOutputCharacterW(
GetStdHandle(STD_OUTPUT_HANDLE),
data.data(), data.size(), pt, &actual);
assert(ret);
data.resize(actual); // With double-width chars, we can read fewer than `size`.
return data;
}
static void dump(const COORD pt, const COORD size) {
for (CHAR_INFO ci : get(pt, size)) {
printf("%04X %04X\n", ci.Char.UnicodeChar, ci.Attributes);
}
}
static void dumpCharsAt(const COORD pt, int size) {
for (wchar_t ch : readCharsAt(pt, size)) {
printf("%04X\n", ch);
}
}
static COORD getCursorPos() {
CONSOLE_SCREEN_BUFFER_INFO info = { sizeof(info) };
assert(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info));
return info.dwCursorPosition;
}
static void test1() {
// We write "䀀䀀", then write "䀁" in the middle of the two. The second
// write turns the first and last cells into spaces. The LEADING/TRAILING
// flags retain consistency.
printf("test1 - overlap full-width char with full-width char\n");
writeCharsAt({1,0}, {0x4000, 0x4000});
dump({0,0}, {6,1});
printf("\n");
writeCharsAt({2,0}, {0x4001});
dump({0,0}, {6,1});
printf("\n");
}
static void test2() {
// Like `test1`, but use a lower-level API to do the write. Consistency is
// preserved here too -- the first and last cells are replaced with spaces.
printf("test2 - overlap full-width char with full-width char (lowlevel)\n");
writeCharsAt({1,0}, {0x4000, 0x4000});
dump({0,0}, {6,1});
printf("\n");
set({2,0}, {ci(0x4001,0x107), ci(0x4001,0x207)});
dump({0,0}, {6,1});
printf("\n");
}
static void test3() {
// However, the lower-level API can break the LEADING/TRAILING invariant
// explicitly:
printf("test3 - explicitly violate LEADING/TRAILING using lowlevel API\n");
set({1,0}, {
ci(0x4000, 0x207),
ci(0x4001, 0x107),
ci(0x3044, 7),
ci(L'X', 0x107),
ci(L'X', 0x207),
});
dump({0,0}, {7,1});
}
static void test4() {
// It is possible for the two cells of a double-width character to have two
// colors.
printf("test4 - use lowlevel to assign two colors to one full-width char\n");
set({0,0}, {
ci(0x4000, 0x142),
ci(0x4000, 0x224),
});
dump({0,0}, {2,1});
}
static void test5() {
// WriteConsoleOutputAttribute doesn't seem to affect the LEADING/TRAILING
// flags.
printf("test5 - WriteConsoleOutputAttribute cannot affect LEADING/TRAILING\n");
// Trying to clear the flags doesn't work...
writeCharsAt({0,0}, {0x4000});
dump({0,0}, {2,1});
writeAttrsAt({0,0}, {0x42, 0x24});
printf("\n");
dump({0,0}, {2,1});
// ... and trying to add them also doesn't work.
writeCharsAt({0,1}, {'A', ' '});
writeAttrsAt({0,1}, {0x107, 0x207});
printf("\n");
dump({0,1}, {2,1});
}
static void test6() {
// The cursor position may be on either cell of a double-width character.
// Visually, the cursor appears under both cells, regardless of which
// specific one has the cursor.
printf("test6 - cursor can be either left or right cell of full-width char\n");
writeCharsAt({2,1}, {0x4000});
setCursorPos(2, 1);
auto pos1 = getCursorPos();
Sleep(1000);
setCursorPos(3, 1);
auto pos2 = getCursorPos();
Sleep(1000);
setCursorPos(0, 15);
printf("%d,%d\n", pos1.X, pos1.Y);
printf("%d,%d\n", pos2.X, pos2.Y);
}
static void runTest(void (&test)()) {
system("cls");
setCursorPos(0, 14);
test();
system("pause");
}
int main(int argc, char *argv[]) {
if (argc == 1) {
startChildProcess(L"CHILD");
return 0;
}
setWindowPos(0, 0, 1, 1);
setBufferSize(80, 40);
setWindowPos(0, 0, 80, 40);
auto cp = GetConsoleOutputCP();
assert(cp == 932 || cp == 936 || cp == 949 || cp == 950);
runTest(test1);
runTest(test2);
runTest(test3);
runTest(test4);
runTest(test5);
runTest(test6);
return 0;
}

View File

@@ -0,0 +1,130 @@
//
// Test half-width vs full-width characters.
//
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include "TestUtil.cc"
static void writeChars(const wchar_t *text) {
wcslen(text);
const int len = wcslen(text);
DWORD actual = 0;
BOOL ret = WriteConsoleW(
GetStdHandle(STD_OUTPUT_HANDLE),
text, len, &actual, NULL);
trace("writeChars: ret=%d, actual=%lld", ret, (long long)actual);
}
static void dumpChars(int x, int y, int w, int h) {
BOOL ret;
const COORD bufSize = {w, h};
const COORD bufCoord = {0, 0};
const SMALL_RECT topLeft = {x, y, x + w - 1, y + h - 1};
CHAR_INFO mbcsData[w * h];
CHAR_INFO unicodeData[w * h];
SMALL_RECT readRegion;
readRegion = topLeft;
ret = ReadConsoleOutputW(GetStdHandle(STD_OUTPUT_HANDLE), unicodeData,
bufSize, bufCoord, &readRegion);
assert(ret);
readRegion = topLeft;
ret = ReadConsoleOutputA(GetStdHandle(STD_OUTPUT_HANDLE), mbcsData,
bufSize, bufCoord, &readRegion);
assert(ret);
printf("\n");
for (int i = 0; i < w * h; ++i) {
printf("(%02d,%02d) CHAR: %04x %4x -- %02x %4x\n",
x + i % w, y + i / w,
(unsigned short)unicodeData[i].Char.UnicodeChar,
(unsigned short)unicodeData[i].Attributes,
(unsigned char)mbcsData[i].Char.AsciiChar,
(unsigned short)mbcsData[i].Attributes);
}
}
int main(int argc, char *argv[]) {
system("cls");
setWindowPos(0, 0, 1, 1);
setBufferSize(80, 38);
setWindowPos(0, 0, 80, 38);
// Write text.
const wchar_t text1[] = {
0x3044, // U+3044 (HIRAGANA LETTER I)
0x2014, // U+2014 (EM DASH)
0x3044, // U+3044 (HIRAGANA LETTER I)
0xFF2D, // U+FF2D (FULLWIDTH LATIN CAPITAL LETTER M)
0x30FC, // U+30FC (KATAKANA-HIRAGANA PROLONGED SOUND MARK)
0x0031, // U+3031 (DIGIT ONE)
0x2014, // U+2014 (EM DASH)
0x0032, // U+0032 (DIGIT TWO)
0x005C, // U+005C (REVERSE SOLIDUS)
0x3044, // U+3044 (HIRAGANA LETTER I)
0
};
setCursorPos(0, 0);
writeChars(text1);
setCursorPos(78, 1);
writeChars(L"<>");
const wchar_t text2[] = {
0x0032, // U+3032 (DIGIT TWO)
0x3044, // U+3044 (HIRAGANA LETTER I)
0,
};
setCursorPos(78, 1);
writeChars(text2);
system("pause");
dumpChars(0, 0, 17, 1);
dumpChars(2, 0, 2, 1);
dumpChars(2, 0, 1, 1);
dumpChars(3, 0, 1, 1);
dumpChars(78, 1, 2, 1);
dumpChars(0, 2, 2, 1);
system("pause");
system("cls");
const wchar_t text3[] = {
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 1
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 2
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 3
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 4
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 5
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 6
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 7
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 8
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 9
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 10
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 11
0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 12
L'\r', '\n',
L'\r', '\n',
0
};
writeChars(text3);
system("pause");
{
const COORD bufSize = {80, 2};
const COORD bufCoord = {0, 0};
SMALL_RECT readRegion = {0, 0, 79, 1};
CHAR_INFO unicodeData[160];
BOOL ret = ReadConsoleOutputW(GetStdHandle(STD_OUTPUT_HANDLE), unicodeData,
bufSize, bufCoord, &readRegion);
assert(ret);
for (int i = 0; i < 96; ++i) {
printf("%04x ", unicodeData[i].Char.UnicodeChar);
}
printf("\n");
}
return 0;
}

View File

@@ -0,0 +1,89 @@
/*
* Unix test code that puts the terminal into raw mode, then echos typed
* characters to stdout. Derived from sample code in the Stevens book, posted
* online at http://www.lafn.org/~dave/linux/terminalIO.html.
*/
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "FormatChar.h"
static struct termios save_termios;
static int term_saved;
/* RAW! mode */
int tty_raw(int fd)
{
struct termios buf;
if (tcgetattr(fd, &save_termios) < 0) /* get the original state */
return -1;
buf = save_termios;
/* echo off, canonical mode off, extended input
processing off, signal chars off */
buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* no SIGINT on BREAK, CR-to-NL off, input parity
check off, don't strip the 8th bit on input,
ouput flow control off */
buf.c_iflag &= ~(BRKINT | ICRNL | ISTRIP | IXON);
/* clear size bits, parity checking off */
buf.c_cflag &= ~(CSIZE | PARENB);
/* set 8 bits/char */
buf.c_cflag |= CS8;
/* output processing off */
buf.c_oflag &= ~(OPOST);
buf.c_cc[VMIN] = 1; /* 1 byte at a time */
buf.c_cc[VTIME] = 0; /* no timer on input */
if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
return -1;
term_saved = 1;
return 0;
}
/* set it to normal! */
int tty_reset(int fd)
{
if (term_saved)
if (tcsetattr(fd, TCSAFLUSH, &save_termios) < 0)
return -1;
return 0;
}
int main()
{
tty_raw(0);
int count = 0;
while (true) {
char ch;
char buf[16];
int actual = read(0, &ch, 1);
if (actual != 1) {
perror("read error");
break;
}
formatChar(buf, ch);
fputs(buf, stdout);
fflush(stdout);
if (ch == 3) // Ctrl-C
break;
}
tty_reset(0);
return 0;
}

View File

@@ -0,0 +1,46 @@
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <string>
int main(int argc, char *argv[]) {
system("cls");
if (argc == 1) {
printf("Usage: %s hhhh\n", argv[0]);
return 0;
}
std::wstring dataToWrite;
for (int i = 1; i < argc; ++i) {
wchar_t ch = strtol(argv[i], NULL, 16);
dataToWrite.push_back(ch);
}
DWORD actual = 0;
BOOL ret = WriteConsoleW(
GetStdHandle(STD_OUTPUT_HANDLE),
dataToWrite.data(), dataToWrite.size(), &actual, NULL);
assert(ret && actual == dataToWrite.size());
// Read it back.
std::vector<CHAR_INFO> readBuffer(dataToWrite.size() * 2);
COORD bufSize = {static_cast<short>(readBuffer.size()), 1};
COORD bufCoord = {0, 0};
SMALL_RECT topLeft = {0, 0, static_cast<short>(readBuffer.size() - 1), 0};
ret = ReadConsoleOutputW(
GetStdHandle(STD_OUTPUT_HANDLE), readBuffer.data(),
bufSize, bufCoord, &topLeft);
assert(ret);
printf("\n");
for (int i = 0; i < readBuffer.size(); ++i) {
printf("CHAR: %04x %04x\n",
readBuffer[i].Char.UnicodeChar,
readBuffer[i].Attributes);
}
return 0;
}

View File

@@ -0,0 +1,122 @@
//
// 2015-09-25
// I measured these limits on the size of a single ReadConsoleOutputW call.
// The limit seems to more-or-less disppear with Windows 8, which is the first
// OS to stop using ALPCs for console I/O. My guess is that the new I/O
// method does not use the 64KiB shared memory buffer that the ALPC method
// uses.
//
// I'm guessing the remaining difference between Windows 8/8.1 and Windows 10
// might be related to the 32-vs-64-bitness.
//
// Client OSs
//
// Windows XP 32-bit VM ==> up to 13304 characters
// - 13304x1 works, but 13305x1 fails instantly
// Windows 7 32-bit VM ==> between 16-17 thousand characters
// - 16000x1 works, 17000x1 fails instantly
// - 163x100 *crashes* conhost.exe but leaves VeryLargeRead.exe running
// Windows 8 32-bit VM ==> between 240-250 million characters
// - 10000x24000 works, but 10000x25000 does not
// Windows 8.1 32-bit VM ==> between 240-250 million characters
// - 10000x24000 works, but 10000x25000 does not
// Windows 10 64-bit VM ==> no limit (tested to 576 million characters)
// - 24000x24000 works
// - `ver` reports [Version 10.0.10240], conhost.exe and ConhostV1.dll are
// 10.0.10240.16384 for file and product version. ConhostV2.dll is
// 10.0.10240.16391 for file and product version.
//
// Server OSs
//
// Windows Server 2008 64-bit VM ==> 14300-14400 characters
// - 14300x1 works, 14400x1 fails instantly
// - This OS does not have conhost.exe.
// - `ver` reports [Version 6.0.6002]
// Windows Server 2008 R2 64-bit VM ==> 15600-15700 characters
// - 15600x1 works, 15700x1 fails instantly
// - This OS has conhost.exe, and procexp.exe reveals console ALPC ports in
// use in conhost.exe.
// - `ver` reports [Version 6.1.7601], conhost.exe is 6.1.7601.23153 for file
// and product version.
// Windows Server 2012 64-bit VM ==> at least 100 million characters
// - 10000x10000 works (VM had only 1GiB of RAM, so I skipped larger tests)
// - This OS has Windows 8's task manager and procexp.exe reveals the same
// lack of ALPC ports and the same \Device\ConDrv\* files as Windows 8.
// - `ver` reports [Version 6.2.9200], conhost.exe is 6.2.9200.16579 for file
// and product version.
//
// To summarize:
//
// client-OS server-OS notes
// ---------------------------------------------------------------------------
// XP Server 2008 CSRSS, small reads
// 7 Server 2008 R2 ALPC-to-conhost, small reads
// 8, 8.1 Server 2012 new I/O interface, large reads allowed
// 10 <no server OS yet> enhanced console w/rewrapping
//
// (Presumably, Win2K, Vista, and Win2K3 behave the same as XP. conhost.exe
// was announced as a Win7 feature.)
//
#include <windows.h>
#include <assert.h>
#include <vector>
#include "TestUtil.cc"
int main(int argc, char *argv[]) {
long long width = 9000;
long long height = 9000;
assert(argc >= 1);
if (argc == 4) {
width = atoi(argv[2]);
height = atoi(argv[3]);
} else {
if (argc == 3) {
width = atoi(argv[1]);
height = atoi(argv[2]);
}
wchar_t args[1024];
swprintf(args, 1024, L"CHILD %lld %lld", width, height);
startChildProcess(args);
return 0;
}
const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
setWindowPos(0, 0, 1, 1);
setBufferSize(width, height);
setWindowPos(0, 0, std::min(80LL, width), std::min(50LL, height));
setCursorPos(0, 0);
printf("A");
fflush(stdout);
setCursorPos(width - 2, height - 1);
printf("B");
fflush(stdout);
trace("sizeof(CHAR_INFO) = %d", (int)sizeof(CHAR_INFO));
trace("Allocating buffer...");
CHAR_INFO *buffer = new CHAR_INFO[width * height];
assert(buffer != NULL);
memset(&buffer[0], 0, sizeof(CHAR_INFO));
memset(&buffer[width * height - 2], 0, sizeof(CHAR_INFO));
COORD bufSize = { width, height };
COORD bufCoord = { 0, 0 };
SMALL_RECT readRegion = { 0, 0, width - 1, height - 1 };
trace("ReadConsoleOutputW: calling...");
BOOL success = ReadConsoleOutputW(conout, buffer, bufSize, bufCoord, &readRegion);
trace("ReadConsoleOutputW: success=%d", success);
assert(buffer[0].Char.UnicodeChar == L'A');
assert(buffer[width * height - 2].Char.UnicodeChar == L'B');
trace("Top-left and bottom-right characters read successfully!");
Sleep(30000);
delete [] buffer;
return 0;
}

View File

@@ -0,0 +1,56 @@
/*
* Sending VK_PAUSE to the console window almost works as a mechanism for
* pausing it, but it doesn't because the console could turn off the
* ENABLE_LINE_INPUT console mode flag.
*/
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
CALLBACK DWORD pausingThread(LPVOID dummy)
{
if (1) {
Sleep(1000);
HWND hwnd = GetConsoleWindow();
SendMessage(hwnd, WM_KEYDOWN, VK_PAUSE, 1);
Sleep(1000);
SendMessage(hwnd, WM_KEYDOWN, VK_ESCAPE, 1);
}
if (0) {
INPUT_RECORD ir;
memset(&ir, 0, sizeof(ir));
ir.EventType = KEY_EVENT;
ir.Event.KeyEvent.bKeyDown = TRUE;
ir.Event.KeyEvent.wVirtualKeyCode = VK_PAUSE;
ir.Event.KeyEvent.wRepeatCount = 1;
}
return 0;
}
int main()
{
HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
COORD c = { 0, 0 };
DWORD mode;
GetConsoleMode(hin, &mode);
SetConsoleMode(hin, mode &
~(ENABLE_LINE_INPUT));
CreateThread(NULL, 0,
pausingThread, NULL,
0, NULL);
int i = 0;
while (true) {
Sleep(100);
printf("%d\n", ++i);
}
return 0;
}

View File

@@ -0,0 +1,52 @@
/*
* Demonstrates a conhost hang that occurs when widening the console buffer
* while selection is in progress. The problem affects the new Windows 10
* console, not the "legacy" console mode that Windows 10 also includes.
*
* First tested with:
* - Windows 10.0.10240
* - conhost.exe version 10.0.10240.16384
* - ConhostV1.dll version 10.0.10240.16384
* - ConhostV2.dll version 10.0.10240.16391
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include "TestUtil.cc"
const int SC_CONSOLE_MARK = 0xFFF2;
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
int main(int argc, char *argv[]) {
if (argc == 1) {
startChildProcess(L"CHILD");
return 0;
}
setWindowPos(0, 0, 1, 1);
setBufferSize(80, 25);
setWindowPos(0, 0, 80, 25);
countDown(5);
SendMessage(GetConsoleWindow(), WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0);
Sleep(2000);
// This API call does not return. In the console window, the "Select All"
// operation appears to end. The console window becomes non-responsive,
// and the conhost.exe process must be killed from the Task Manager.
// (Killing this test program or closing the console window is not
// sufficient.)
//
// The same hang occurs whether line resizing is off or on. It happens
// with both "Mark" and "Select All". Calling setBufferSize with the
// existing buffer size does not hang, but calling it with only a changed
// buffer height *does* hang. Calling setWindowPos does not hang.
setBufferSize(120, 25);
printf("Done...\n");
Sleep(2000);
}

View File

@@ -0,0 +1,57 @@
/*
* Demonstrates some wrapping behaviors of the new Windows 10 console.
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "TestUtil.cc"
int main(int argc, char *argv[]) {
if (argc == 1) {
startChildProcess(L"CHILD");
return 0;
}
setWindowPos(0, 0, 1, 1);
setBufferSize(40, 20);
setWindowPos(0, 0, 40, 20);
system("cls");
repeatChar(39, 'A'); repeatChar(1, ' ');
repeatChar(39, 'B'); repeatChar(1, ' ');
printf("\n");
repeatChar(39, 'C'); repeatChar(1, ' ');
repeatChar(39, 'D'); repeatChar(1, ' ');
printf("\n");
repeatChar(40, 'E');
repeatChar(40, 'F');
printf("\n");
repeatChar(39, 'G'); repeatChar(1, ' ');
repeatChar(39, 'H'); repeatChar(1, ' ');
printf("\n");
Sleep(2000);
setChar(39, 0, '*', 0x24);
setChar(39, 1, '*', 0x24);
setChar(39, 3, ' ', 0x24);
setChar(39, 4, ' ', 0x24);
setChar(38, 6, ' ', 0x24);
setChar(38, 7, ' ', 0x24);
Sleep(2000);
setWindowPos(0, 0, 35, 20);
setBufferSize(35, 20);
trace("DONE");
printf("Sleeping forever...\n");
while(true) { Sleep(1000); }
}

Some files were not shown because too many files have changed in this diff Show More