Compare commits
21 Commits
master
...
nodejs_fix
Author | SHA1 | Date | |
---|---|---|---|
|
bbdc8b82ae | ||
|
4f38a876ec | ||
|
86690addf4 | ||
|
25e3186e9e | ||
|
d4b5cb8a33 | ||
|
1db59898e3 | ||
|
efc82affdf | ||
|
9325995ae4 | ||
|
587e5125a7 | ||
|
237c36b7db | ||
|
515dea18de | ||
|
b4fea62fb0 | ||
|
4bdd7b32b5 | ||
|
8aa7662093 | ||
|
1cb199b1f0 | ||
|
3f1bbcd9af | ||
|
7091af176a | ||
|
857ed8934b | ||
|
964f5a63f8 | ||
|
747a5401e8 | ||
|
5363fb6c21 |
20
.gitattributes
vendored
20
.gitattributes
vendored
@ -1,19 +1 @@
|
||||
* 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
|
||||
configure -crlf
|
||||
|
17
.gitignore
vendored
17
.gitignore
vendored
@ -1,16 +1,13 @@
|
||||
*.o
|
||||
*.d
|
||||
*.exe
|
||||
*.dll
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
*.pyc
|
||||
Default
|
||||
winpty.sdf
|
||||
winpty.opensdf
|
||||
/config.mk
|
||||
/build
|
||||
/build-gyp
|
||||
/build-libpty
|
||||
/ship/packages
|
||||
/ship/tmp
|
||||
/src/Default
|
||||
/src/Release
|
||||
/src/gen
|
||||
config-mingw.mk
|
||||
config-unix.mk
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2016 Ryan Prichard
|
||||
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
|
||||
|
153
Makefile
153
Makefile
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2011-2015 Ryan Prichard
|
||||
# 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
|
||||
@ -18,149 +18,22 @@
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
# Use make -n to see the actual command-lines make would run.
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
# The default "make install" prefix is /usr/local. Pass PREFIX=<path> on the
|
||||
# command-line to override the default.
|
||||
all :
|
||||
cd agent && $(MAKE)
|
||||
cd libwinpty && $(MAKE)
|
||||
cd unix-adapter && $(MAKE)
|
||||
|
||||
.SECONDEXPANSION :
|
||||
|
||||
.PHONY : default
|
||||
default : all
|
||||
|
||||
PREFIX := /usr/local
|
||||
UNIX_ADAPTER_EXE := winpty.exe
|
||||
MINGW_ENABLE_CXX11_FLAG := -std=c++11
|
||||
USE_PCH := 1
|
||||
|
||||
COMMON_CXXFLAGS :=
|
||||
UNIX_CXXFLAGS :=
|
||||
MINGW_CXXFLAGS :=
|
||||
MINGW_LDFLAGS :=
|
||||
UNIX_LDFLAGS :=
|
||||
|
||||
# Include config.mk but complain if it hasn't been created yet.
|
||||
ifeq "$(wildcard config.mk)" ""
|
||||
$(error config.mk does not exist. Please run ./configure)
|
||||
endif
|
||||
include config.mk
|
||||
|
||||
COMMON_CXXFLAGS += \
|
||||
-MMD -Wall \
|
||||
-DUNICODE \
|
||||
-D_UNICODE \
|
||||
-D_WIN32_WINNT=0x0501 \
|
||||
-Ibuild/gen
|
||||
|
||||
UNIX_CXXFLAGS += \
|
||||
$(COMMON_CXXFLAGS)
|
||||
|
||||
MINGW_CXXFLAGS += \
|
||||
$(COMMON_CXXFLAGS) \
|
||||
-O2 \
|
||||
$(MINGW_ENABLE_CXX11_FLAG)
|
||||
|
||||
MINGW_LDFLAGS += -static -static-libgcc -static-libstdc++
|
||||
UNIX_LDFLAGS += $(UNIX_LDFLAGS_STATIC)
|
||||
|
||||
ifeq "$(USE_PCH)" "1"
|
||||
MINGW_CXXFLAGS += -include build/mingw/PrecompiledHeader.h
|
||||
PCH_DEP := build/mingw/PrecompiledHeader.h.gch
|
||||
else
|
||||
PCH_DEP :=
|
||||
endif
|
||||
|
||||
build/gen/GenVersion.h : VERSION.txt $(COMMIT_HASH_DEP) | $$(@D)/.mkdir
|
||||
$(info Updating build/gen/GenVersion.h)
|
||||
@echo "const char GenVersion_Version[] = \"$(shell cat VERSION.txt | tr -d '\r\n')\";" > build/gen/GenVersion.h
|
||||
@echo "const char GenVersion_Commit[] = \"$(COMMIT_HASH)\";" >> build/gen/GenVersion.h
|
||||
|
||||
build/mingw/PrecompiledHeader.h : src/shared/PrecompiledHeader.h | $$(@D)/.mkdir
|
||||
$(info Copying $< to $@)
|
||||
@cp $< $@
|
||||
|
||||
build/mingw/PrecompiledHeader.h.gch : build/mingw/PrecompiledHeader.h | $$(@D)/.mkdir
|
||||
$(info Compiling $<)
|
||||
@$(MINGW_CXX) $(MINGW_CXXFLAGS) -c -o $@ $<
|
||||
|
||||
-include build/mingw/PrecompiledHeader.h.d
|
||||
|
||||
define def_unix_target
|
||||
build/$1/%.o : src/%.cc | $$$$(@D)/.mkdir
|
||||
$$(info Compiling $$<)
|
||||
@$$(UNIX_CXX) $$(UNIX_CXXFLAGS) $2 -I src/include -c -o $$@ $$<
|
||||
endef
|
||||
|
||||
define def_mingw_target
|
||||
build/$1/%.o : src/%.cc $$(PCH_DEP) | $$$$(@D)/.mkdir
|
||||
$$(info Compiling $$<)
|
||||
@$$(MINGW_CXX) $$(MINGW_CXXFLAGS) $2 -I src/include -c -o $$@ $$<
|
||||
endef
|
||||
|
||||
include src/subdir.mk
|
||||
|
||||
.PHONY : all
|
||||
all : $(ALL_TARGETS)
|
||||
|
||||
.PHONY : tests
|
||||
tests : $(TEST_PROGRAMS)
|
||||
|
||||
.PHONY : install-bin
|
||||
install-bin : all
|
||||
install : all
|
||||
mkdir -p $(PREFIX)/bin
|
||||
install -m 755 -p -s build/$(UNIX_ADAPTER_EXE) $(PREFIX)/bin
|
||||
install -m 755 -p -s build/winpty.dll $(PREFIX)/bin
|
||||
install -m 755 -p -s build/winpty-agent.exe $(PREFIX)/bin
|
||||
cp build/* $(PREFIX)/bin
|
||||
|
||||
.PHONY : install-debugserver
|
||||
install-debugserver : all
|
||||
mkdir -p $(PREFIX)/bin
|
||||
install -m 755 -p -s build/winpty-debugserver.exe $(PREFIX)/bin
|
||||
|
||||
.PHONY : install-lib
|
||||
install-lib : all
|
||||
mkdir -p $(PREFIX)/lib
|
||||
install -m 644 -p build/winpty.lib $(PREFIX)/lib
|
||||
|
||||
.PHONY : install-doc
|
||||
install-doc :
|
||||
mkdir -p $(PREFIX)/share/doc/winpty
|
||||
install -m 644 -p LICENSE $(PREFIX)/share/doc/winpty
|
||||
install -m 644 -p README.md $(PREFIX)/share/doc/winpty
|
||||
install -m 644 -p RELEASES.md $(PREFIX)/share/doc/winpty
|
||||
|
||||
.PHONY : install-include
|
||||
install-include :
|
||||
mkdir -p $(PREFIX)/include/winpty
|
||||
install -m 644 -p src/include/winpty.h $(PREFIX)/include/winpty
|
||||
install -m 644 -p src/include/winpty_constants.h $(PREFIX)/include/winpty
|
||||
|
||||
.PHONY : install
|
||||
install : \
|
||||
install-bin \
|
||||
install-debugserver \
|
||||
install-lib \
|
||||
install-doc \
|
||||
install-include
|
||||
|
||||
.PHONY : clean
|
||||
clean :
|
||||
rm -fr build
|
||||
cd agent && $(MAKE) clean
|
||||
cd libwinpty && $(MAKE) clean
|
||||
cd unix-adapter && $(MAKE) clean
|
||||
|
||||
.PHONY : clean-msvc
|
||||
clean-msvc :
|
||||
rm -fr src/Default src/Release src/.vs src/gen
|
||||
rm -f src/*.vcxproj src/*.vcxproj.filters src/*.sln src/*.sdf
|
||||
|
||||
.PHONY : distclean
|
||||
distclean : clean
|
||||
rm -f config.mk
|
||||
|
||||
.PRECIOUS : %.mkdir
|
||||
%.mkdir :
|
||||
$(info Creating directory $(dir $@))
|
||||
@mkdir -p $(dir $@)
|
||||
@touch $@
|
||||
|
||||
src/%.h :
|
||||
@echo "Missing header file $@ (stale dependency file?)"
|
||||
rm -f config-unix.mk
|
||||
rm -f config-mingw.mk
|
||||
|
151
README.md
151
README.md
@ -1,151 +0,0 @@
|
||||
# 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.
|
90
README.rst
Normal file
90
README.rst
Normal file
@ -0,0 +1,90 @@
|
||||
======
|
||||
winpty
|
||||
======
|
||||
|
||||
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.
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
You need the following to build winpty:
|
||||
|
||||
* A Cygwin or MSYS installation
|
||||
* GNU make
|
||||
* A MinGW 32-bit g++ toolchain, v4 or later, to build ``winpty.dll`` and
|
||||
``winpty-agent.exe``
|
||||
* A g++ toolchain targeting Cygwin or MSYS, v3 or later, to build
|
||||
``console.exe``
|
||||
|
||||
Winpty requires two g++ toolchains as it is split into two parts. The
|
||||
binaries winpty.dll and winpty-agent.exe interface with the native Windows
|
||||
command prompt window so they are compiled with the native MinGW toolchain.
|
||||
The console.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 acceptable, but the compiler must be v4 or later and produce 32-bit
|
||||
binaries.
|
||||
|
||||
Cygwin packages
|
||||
---------------
|
||||
|
||||
The default g++ compiler for Cygwin targets Cygwin itself, but Cygwin also
|
||||
packages MinGW compilers from both the MinGW and MinGW-w64 projects. As of
|
||||
this writing, the necessary packages are:
|
||||
|
||||
* Either ``mingw-gcc-g++`` or ``mingw64-i686-gcc-g++`` (but not
|
||||
``mingw64-x86_64-gcc-g++``)
|
||||
* ``gcc4-g++``
|
||||
|
||||
MinGW packages
|
||||
--------------
|
||||
|
||||
The default g++ compiler for MinGW targets native Windows, but the MinGW
|
||||
project also packages compilers to target the MSYS environment itself. The
|
||||
required packages are:
|
||||
|
||||
* ``mingw32-make``
|
||||
* ``g++``
|
||||
* ``msys-dvlpr``
|
||||
|
||||
|
||||
Build
|
||||
=====
|
||||
|
||||
In the project directory, run ``./configure``, then ``make``.
|
||||
|
||||
This will produce three binaries:
|
||||
|
||||
* ``build/winpty.dll``
|
||||
* ``build/winpty-agent.exe``
|
||||
* ``build/console.exe``
|
||||
|
||||
Using the Unix adapter
|
||||
======================
|
||||
|
||||
To run a Windows console program in ``mintty`` or Cygwin ``sshd``, prepend
|
||||
``console.exe`` to the command-line::
|
||||
|
||||
$ build/console.exe c:/Python27/python.exe
|
||||
Python 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] on win32
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> 10 + 20
|
||||
30
|
||||
>>> exit()
|
||||
$
|
280
RELEASES.md
280
RELEASES.md
@ -1,280 +0,0 @@
|
||||
# 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 +0,0 @@
|
||||
0.4.4-dev
|
518
agent/Agent.cc
Normal file
518
agent/Agent.cc
Normal file
@ -0,0 +1,518 @@
|
||||
// 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.
|
||||
|
||||
#include "Agent.h"
|
||||
#include "Win32Console.h"
|
||||
#include "ConsoleInput.h"
|
||||
#include "Terminal.h"
|
||||
#include "NamedPipe.h"
|
||||
#include "AgentAssert.h"
|
||||
#include "../shared/DebugClient.h"
|
||||
#include "../shared/AgentMsg.h"
|
||||
#include "../shared/Buffer.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
const int SC_CONSOLE_MARK = 0xFFF2;
|
||||
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
|
||||
const int SYNC_MARKER_LEN = 16;
|
||||
|
||||
static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)
|
||||
{
|
||||
if (dwCtrlType == CTRL_C_EVENT) {
|
||||
// Do nothing and claim to have handled the event.
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Agent::Agent(LPCWSTR controlPipeName,
|
||||
LPCWSTR dataPipeName,
|
||||
int initialCols,
|
||||
int initialRows) :
|
||||
m_closingDataSocket(false),
|
||||
m_terminal(NULL),
|
||||
m_childProcess(NULL),
|
||||
m_childExitCode(-1),
|
||||
m_syncCounter(0)
|
||||
{
|
||||
trace("Agent starting...");
|
||||
|
||||
m_bufferData = new CHAR_INFO[BUFFER_LINE_COUNT][MAX_CONSOLE_WIDTH];
|
||||
|
||||
m_console = new Win32Console;
|
||||
m_console->setSmallFont();
|
||||
m_console->reposition(
|
||||
Coord(initialCols, BUFFER_LINE_COUNT),
|
||||
SmallRect(0, 0, initialCols, initialRows));
|
||||
m_console->setCursorPosition(Coord(0, 0));
|
||||
|
||||
m_controlSocket = makeSocket(controlPipeName);
|
||||
m_dataSocket = makeSocket(dataPipeName);
|
||||
m_terminal = new Terminal(m_dataSocket);
|
||||
m_consoleInput = new ConsoleInput(m_console, this);
|
||||
|
||||
resetConsoleTracking(false);
|
||||
|
||||
// Setup Ctrl-C handling. First restore default handling of Ctrl-C. This
|
||||
// attribute is inherited by child processes. Then register a custom
|
||||
// Ctrl-C handler that does nothing. The handler will be called when the
|
||||
// agent calls GenerateConsoleCtrlEvent.
|
||||
SetConsoleCtrlHandler(NULL, FALSE);
|
||||
SetConsoleCtrlHandler(consoleCtrlHandler, TRUE);
|
||||
|
||||
setPollInterval(25);
|
||||
}
|
||||
|
||||
Agent::~Agent()
|
||||
{
|
||||
trace("Agent exiting...");
|
||||
m_console->postCloseMessage();
|
||||
if (m_childProcess != NULL)
|
||||
CloseHandle(m_childProcess);
|
||||
delete [] m_bufferData;
|
||||
delete m_console;
|
||||
delete m_terminal;
|
||||
delete m_consoleInput;
|
||||
}
|
||||
|
||||
// Write a "Device Status Report" command to the terminal. The terminal will
|
||||
// reply with a row+col escape sequence. Presumably, the DSR reply will not
|
||||
// split a keypress escape sequence, so it should be safe to assume that the
|
||||
// bytes before it are complete keypresses.
|
||||
void Agent::sendDsr()
|
||||
{
|
||||
m_dataSocket->write("\x1B[6n");
|
||||
}
|
||||
|
||||
NamedPipe *Agent::makeSocket(LPCWSTR pipeName)
|
||||
{
|
||||
NamedPipe *pipe = createNamedPipe();
|
||||
if (!pipe->connectToServer(pipeName)) {
|
||||
trace("error: could not connect to %ls", pipeName);
|
||||
::exit(1);
|
||||
}
|
||||
pipe->setReadBufferSize(64 * 1024);
|
||||
return pipe;
|
||||
}
|
||||
|
||||
void Agent::resetConsoleTracking(bool sendClear)
|
||||
{
|
||||
memset(m_bufferData, 0, sizeof(CHAR_INFO) * BUFFER_LINE_COUNT * MAX_CONSOLE_WIDTH);
|
||||
m_syncRow = -1;
|
||||
m_scrapedLineCount = m_console->windowRect().top();
|
||||
m_scrolledCount = 0;
|
||||
m_maxBufferedLine = -1;
|
||||
m_dirtyWindowTop = -1;
|
||||
m_dirtyLineCount = 0;
|
||||
m_terminal->reset(sendClear, m_scrapedLineCount);
|
||||
}
|
||||
|
||||
void Agent::onPipeIo(NamedPipe *namedPipe)
|
||||
{
|
||||
if (namedPipe == m_controlSocket)
|
||||
pollControlSocket();
|
||||
else if (namedPipe == m_dataSocket)
|
||||
pollDataSocket();
|
||||
}
|
||||
|
||||
void Agent::pollControlSocket()
|
||||
{
|
||||
if (m_controlSocket->isClosed()) {
|
||||
trace("Agent shutting down");
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
int32_t packetSize;
|
||||
int size = m_controlSocket->peek((char*)&packetSize, sizeof(int32_t));
|
||||
if (size < (int)sizeof(int32_t))
|
||||
break;
|
||||
int totalSize = sizeof(int32_t) + packetSize;
|
||||
if (m_controlSocket->bytesAvailable() < totalSize) {
|
||||
if (m_controlSocket->readBufferSize() < totalSize)
|
||||
m_controlSocket->setReadBufferSize(totalSize);
|
||||
break;
|
||||
}
|
||||
std::string packetData = m_controlSocket->read(totalSize);
|
||||
ASSERT((int)packetData.size() == totalSize);
|
||||
ReadBuffer buffer(packetData);
|
||||
buffer.getInt(); // Discard the size.
|
||||
handlePacket(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Agent::handlePacket(ReadBuffer &packet)
|
||||
{
|
||||
int type = packet.getInt();
|
||||
int32_t result = -1;
|
||||
switch (type) {
|
||||
case AgentMsg::Ping:
|
||||
result = 0;
|
||||
break;
|
||||
case AgentMsg::StartProcess:
|
||||
result = handleStartProcessPacket(packet);
|
||||
break;
|
||||
case AgentMsg::SetSize:
|
||||
result = handleSetSizePacket(packet);
|
||||
break;
|
||||
case AgentMsg::GetExitCode:
|
||||
ASSERT(packet.eof());
|
||||
result = m_childExitCode;
|
||||
break;
|
||||
default:
|
||||
trace("Unrecognized message, id:%d", type);
|
||||
}
|
||||
m_controlSocket->write((char*)&result, sizeof(result));
|
||||
}
|
||||
|
||||
int Agent::handleStartProcessPacket(ReadBuffer &packet)
|
||||
{
|
||||
BOOL success;
|
||||
ASSERT(m_childProcess == NULL);
|
||||
|
||||
std::wstring program = packet.getWString();
|
||||
std::wstring cmdline = packet.getWString();
|
||||
std::wstring cwd = packet.getWString();
|
||||
std::wstring env = packet.getWString();
|
||||
std::wstring desktop = packet.getWString();
|
||||
ASSERT(packet.eof());
|
||||
|
||||
LPCWSTR programArg = program.empty() ? NULL : program.c_str();
|
||||
std::vector<wchar_t> cmdlineCopy;
|
||||
LPWSTR cmdlineArg = NULL;
|
||||
if (!cmdline.empty()) {
|
||||
cmdlineCopy.resize(cmdline.size() + 1);
|
||||
cmdline.copy(&cmdlineCopy[0], cmdline.size());
|
||||
cmdlineCopy[cmdline.size()] = L'\0';
|
||||
cmdlineArg = &cmdlineCopy[0];
|
||||
}
|
||||
LPCWSTR cwdArg = cwd.empty() ? NULL : cwd.c_str();
|
||||
LPCWSTR envArg = env.empty() ? NULL : env.c_str();
|
||||
|
||||
if(envArg != NULL && wcscmp(envArg, L"")) {
|
||||
envArg = NULL;
|
||||
}
|
||||
|
||||
STARTUPINFO sui;
|
||||
PROCESS_INFORMATION pi;
|
||||
memset(&sui, 0, sizeof(sui));
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
sui.cb = sizeof(STARTUPINFO);
|
||||
sui.lpDesktop = desktop.empty() ? NULL : (LPWSTR)desktop.c_str();
|
||||
|
||||
success = CreateProcess(programArg, cmdlineArg, NULL, NULL,
|
||||
/*bInheritHandles=*/FALSE,
|
||||
/*dwCreationFlags=*/CREATE_UNICODE_ENVIRONMENT |
|
||||
/*CREATE_NEW_PROCESS_GROUP*/0,
|
||||
(LPVOID)envArg, cwdArg, &sui, &pi);
|
||||
int ret = success ? 0 : GetLastError();
|
||||
|
||||
trace("CreateProcess: %s %d",
|
||||
(success ? "success" : "fail"),
|
||||
(int)pi.dwProcessId);
|
||||
|
||||
if (success) {
|
||||
CloseHandle(pi.hThread);
|
||||
m_childProcess = pi.hProcess;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Agent::handleSetSizePacket(ReadBuffer &packet)
|
||||
{
|
||||
int cols = packet.getInt();
|
||||
int rows = packet.getInt();
|
||||
ASSERT(packet.eof());
|
||||
resizeWindow(cols, rows);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Agent::pollDataSocket()
|
||||
{
|
||||
m_consoleInput->writeInput(m_dataSocket->readAll());
|
||||
|
||||
// If the child process had exited, then close the data socket if we've
|
||||
// finished sending all of the collected output.
|
||||
if (m_closingDataSocket &&
|
||||
!m_dataSocket->isClosed() &&
|
||||
m_dataSocket->bytesToSend() == 0) {
|
||||
trace("Closing data pipe after data is sent");
|
||||
m_dataSocket->closePipe();
|
||||
}
|
||||
}
|
||||
|
||||
void Agent::onPollTimeout()
|
||||
{
|
||||
// Give the ConsoleInput object a chance to flush input from an incomplete
|
||||
// escape sequence (e.g. pressing ESC).
|
||||
m_consoleInput->flushIncompleteEscapeCode();
|
||||
|
||||
// Check if the child process has exited.
|
||||
if (WaitForSingleObject(m_childProcess, 0) == WAIT_OBJECT_0) {
|
||||
DWORD exitCode;
|
||||
if (GetExitCodeProcess(m_childProcess, &exitCode))
|
||||
m_childExitCode = exitCode;
|
||||
CloseHandle(m_childProcess);
|
||||
m_childProcess = NULL;
|
||||
|
||||
// Close the data socket to signal to the client that the child
|
||||
// process has exited. If there's any data left to send, send it
|
||||
// before closing the socket.
|
||||
m_closingDataSocket = true;
|
||||
}
|
||||
|
||||
// Scrape for output *after* the above exit-check to ensure that we collect
|
||||
// the child process's final output.
|
||||
if (!m_dataSocket->isClosed())
|
||||
scrapeOutput();
|
||||
|
||||
if (m_closingDataSocket &&
|
||||
!m_dataSocket->isClosed() &&
|
||||
m_dataSocket->bytesToSend() == 0) {
|
||||
trace("Closing data pipe after child exit");
|
||||
m_dataSocket->closePipe();
|
||||
}
|
||||
}
|
||||
|
||||
// Detect window movement. If the window moves down (presumably as a
|
||||
// result of scrolling), then assume that all screen buffer lines down to
|
||||
// the bottom of the window are dirty.
|
||||
void Agent::markEntireWindowDirty()
|
||||
{
|
||||
SmallRect windowRect = m_console->windowRect();
|
||||
m_dirtyLineCount = std::max(m_dirtyLineCount,
|
||||
windowRect.top() + windowRect.height());
|
||||
}
|
||||
|
||||
// Scan the screen buffer and advance the dirty line count when we find
|
||||
// non-empty lines.
|
||||
void Agent::scanForDirtyLines()
|
||||
{
|
||||
const SmallRect windowRect = m_console->windowRect();
|
||||
CHAR_INFO prevChar;
|
||||
if (m_dirtyLineCount >= 1) {
|
||||
m_console->read(SmallRect(windowRect.width() - 1,
|
||||
m_dirtyLineCount - 1,
|
||||
1, 1),
|
||||
&prevChar);
|
||||
} else {
|
||||
m_console->read(SmallRect(0, 0, 1, 1), &prevChar);
|
||||
}
|
||||
int attr = prevChar.Attributes;
|
||||
|
||||
for (int line = m_dirtyLineCount;
|
||||
line < windowRect.top() + windowRect.height();
|
||||
++line) {
|
||||
CHAR_INFO lineData[MAX_CONSOLE_WIDTH]; // TODO: bufoverflow
|
||||
SmallRect lineRect(0, line, windowRect.width(), 1);
|
||||
m_console->read(lineRect, lineData);
|
||||
for (int col = 0; col < windowRect.width(); ++col) {
|
||||
int newAttr = lineData[col].Attributes;
|
||||
if (lineData[col].Char.AsciiChar != ' ' || attr!= newAttr)
|
||||
m_dirtyLineCount = line + 1;
|
||||
newAttr = attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Agent::resizeWindow(int cols, int rows)
|
||||
{
|
||||
freezeConsole();
|
||||
|
||||
Coord bufferSize = m_console->bufferSize();
|
||||
SmallRect windowRect = m_console->windowRect();
|
||||
Coord newBufferSize(cols, bufferSize.Y);
|
||||
SmallRect newWindowRect;
|
||||
|
||||
// This resize behavior appears to match what happens when I resize the
|
||||
// console window by hand.
|
||||
if (windowRect.top() + windowRect.height() == bufferSize.Y ||
|
||||
windowRect.top() + rows >= bufferSize.Y) {
|
||||
// Lock the bottom of the new window to the bottom of the buffer if either
|
||||
// - the window was already at the bottom of the buffer, OR
|
||||
// - there isn't enough room.
|
||||
newWindowRect = SmallRect(0, newBufferSize.Y - rows, cols, rows);
|
||||
} else {
|
||||
// Keep the top of the window where it is.
|
||||
newWindowRect = SmallRect(0, windowRect.top(), cols, rows);
|
||||
}
|
||||
|
||||
if (m_dirtyWindowTop != -1 && m_dirtyWindowTop < windowRect.top())
|
||||
markEntireWindowDirty();
|
||||
m_dirtyWindowTop = newWindowRect.top();
|
||||
|
||||
m_console->reposition(newBufferSize, newWindowRect);
|
||||
unfreezeConsole();
|
||||
}
|
||||
|
||||
void Agent::scrapeOutput()
|
||||
{
|
||||
freezeConsole();
|
||||
|
||||
const Coord cursor = m_console->cursorPosition();
|
||||
const SmallRect windowRect = m_console->windowRect();
|
||||
|
||||
if (m_syncRow != -1) {
|
||||
// If a synchronizing marker was placed into the history, look for it
|
||||
// and adjust the scroll count.
|
||||
int markerRow = findSyncMarker();
|
||||
if (markerRow == -1) {
|
||||
// Something has happened. Reset the terminal.
|
||||
trace("Sync marker has disappeared -- resetting the terminal");
|
||||
resetConsoleTracking();
|
||||
} else if (markerRow != m_syncRow) {
|
||||
ASSERT(markerRow < m_syncRow);
|
||||
m_scrolledCount += (m_syncRow - markerRow);
|
||||
m_syncRow = markerRow;
|
||||
// If the buffer has scrolled, then the entire window is dirty.
|
||||
markEntireWindowDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the dirty line count:
|
||||
// - If the window has moved, the entire window is dirty.
|
||||
// - Everything up to the cursor is dirty.
|
||||
// - All lines above the window are dirty.
|
||||
// - Any non-blank lines are dirty.
|
||||
if (m_dirtyWindowTop != -1) {
|
||||
if (windowRect.top() > m_dirtyWindowTop) {
|
||||
// The window has moved down, presumably as a result of scrolling.
|
||||
markEntireWindowDirty();
|
||||
} else if (windowRect.top() < m_dirtyWindowTop) {
|
||||
// The window has moved upward. This is generally not expected to
|
||||
// happen, but the CMD/PowerShell CLS command will move the window
|
||||
// to the top as part of clearing everything else in the console.
|
||||
trace("Window moved upward -- resetting the terminal");
|
||||
resetConsoleTracking();
|
||||
}
|
||||
}
|
||||
m_dirtyWindowTop = windowRect.top();
|
||||
m_dirtyLineCount = std::max(m_dirtyLineCount, cursor.Y + 1);
|
||||
m_dirtyLineCount = std::max(m_dirtyLineCount, (int)windowRect.top());
|
||||
scanForDirtyLines();
|
||||
|
||||
// Note that it's possible for all the lines on the current window to
|
||||
// be non-dirty.
|
||||
|
||||
int firstLine = std::min(m_scrapedLineCount,
|
||||
windowRect.top() + m_scrolledCount);
|
||||
int stopLine = std::min(m_dirtyLineCount,
|
||||
windowRect.top() + windowRect.height()) +
|
||||
m_scrolledCount;
|
||||
|
||||
bool sawModifiedLine = false;
|
||||
|
||||
for (int line = firstLine; line < stopLine; ++line) {
|
||||
CHAR_INFO curLine[MAX_CONSOLE_WIDTH]; // TODO: bufoverflow
|
||||
const int w = windowRect.width();
|
||||
m_console->read(SmallRect(0, line - m_scrolledCount, w, 1), curLine);
|
||||
|
||||
// TODO: The memcpy can overflow the m_bufferData buffer.
|
||||
CHAR_INFO (&bufLine)[MAX_CONSOLE_WIDTH] =
|
||||
m_bufferData[line % BUFFER_LINE_COUNT];
|
||||
if (sawModifiedLine ||
|
||||
line > m_maxBufferedLine ||
|
||||
memcmp(curLine, bufLine, sizeof(CHAR_INFO) * w) != 0) {
|
||||
//trace("sent line %d", line);
|
||||
m_terminal->sendLine(line, curLine, windowRect.width());
|
||||
memset(bufLine, 0, sizeof(bufLine));
|
||||
memcpy(bufLine, curLine, sizeof(CHAR_INFO) * w);
|
||||
for (int col = w; col < MAX_CONSOLE_WIDTH; ++col) {
|
||||
bufLine[col].Attributes = curLine[w - 1].Attributes;
|
||||
bufLine[col].Char.AsciiChar = ' ';
|
||||
}
|
||||
m_maxBufferedLine = std::max(m_maxBufferedLine, line);
|
||||
sawModifiedLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_scrapedLineCount = windowRect.top() + m_scrolledCount;
|
||||
|
||||
if (windowRect.top() > 200) { // TODO: replace hard-coded constant
|
||||
createSyncMarker(windowRect.top() - 200);
|
||||
}
|
||||
|
||||
m_terminal->finishOutput(std::pair<int, int>(cursor.X,
|
||||
cursor.Y + m_scrolledCount));
|
||||
|
||||
unfreezeConsole();
|
||||
}
|
||||
|
||||
void Agent::freezeConsole()
|
||||
{
|
||||
SendMessage(m_console->hwnd(), WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0);
|
||||
}
|
||||
|
||||
void Agent::unfreezeConsole()
|
||||
{
|
||||
SendMessage(m_console->hwnd(), WM_CHAR, 27, 0x00010001);
|
||||
}
|
||||
|
||||
void Agent::syncMarkerText(CHAR_INFO *output)
|
||||
{
|
||||
char str[SYNC_MARKER_LEN + 1];// TODO: use a random string
|
||||
sprintf(str, "S*Y*N*C*%08x", m_syncCounter);
|
||||
memset(output, 0, sizeof(CHAR_INFO) * SYNC_MARKER_LEN);
|
||||
for (int i = 0; i < SYNC_MARKER_LEN; ++i) {
|
||||
output[i].Char.AsciiChar = str[i];
|
||||
output[i].Attributes = 7;
|
||||
}
|
||||
}
|
||||
|
||||
int Agent::findSyncMarker()
|
||||
{
|
||||
ASSERT(m_syncRow >= 0);
|
||||
CHAR_INFO marker[SYNC_MARKER_LEN];
|
||||
CHAR_INFO column[BUFFER_LINE_COUNT];
|
||||
syncMarkerText(marker);
|
||||
SmallRect rect(0, 0, 1, m_syncRow + SYNC_MARKER_LEN);
|
||||
m_console->read(rect, column);
|
||||
int i;
|
||||
for (i = m_syncRow; i >= 0; --i) {
|
||||
int j;
|
||||
for (j = 0; j < SYNC_MARKER_LEN; ++j) {
|
||||
if (column[i + j].Char.AsciiChar != marker[j].Char.AsciiChar)
|
||||
break;
|
||||
}
|
||||
if (j == SYNC_MARKER_LEN)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Agent::createSyncMarker(int row)
|
||||
{
|
||||
// Write a new marker.
|
||||
m_syncCounter++;
|
||||
CHAR_INFO marker[SYNC_MARKER_LEN];
|
||||
syncMarkerText(marker);
|
||||
m_syncRow = row;
|
||||
SmallRect markerRect(0, m_syncRow, 1, SYNC_MARKER_LEN);
|
||||
m_console->write(markerRect, marker);
|
||||
}
|
94
agent/Agent.h
Normal file
94
agent/Agent.h
Normal file
@ -0,0 +1,94 @@
|
||||
// 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.
|
||||
|
||||
#ifndef AGENT_H
|
||||
#define AGENT_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "EventLoop.h"
|
||||
#include "DsrSender.h"
|
||||
|
||||
class Win32Console;
|
||||
class ConsoleInput;
|
||||
class Terminal;
|
||||
class ReadBuffer;
|
||||
class NamedPipe;
|
||||
|
||||
const int BUFFER_LINE_COUNT = 3000; // TODO: Use something like 9000.
|
||||
const int MAX_CONSOLE_WIDTH = 500;
|
||||
|
||||
class Agent : public EventLoop, public DsrSender
|
||||
{
|
||||
public:
|
||||
Agent(LPCWSTR controlPipeName,
|
||||
LPCWSTR dataPipeName,
|
||||
int initialCols,
|
||||
int initialRows);
|
||||
virtual ~Agent();
|
||||
void sendDsr();
|
||||
|
||||
private:
|
||||
NamedPipe *makeSocket(LPCWSTR pipeName);
|
||||
void resetConsoleTracking(bool sendClear = true);
|
||||
|
||||
private:
|
||||
void pollControlSocket();
|
||||
void handlePacket(ReadBuffer &packet);
|
||||
int handleStartProcessPacket(ReadBuffer &packet);
|
||||
int handleSetSizePacket(ReadBuffer &packet);
|
||||
void pollDataSocket();
|
||||
|
||||
protected:
|
||||
virtual void onPollTimeout();
|
||||
virtual void onPipeIo(NamedPipe *namedPipe);
|
||||
|
||||
private:
|
||||
void markEntireWindowDirty();
|
||||
void scanForDirtyLines();
|
||||
void resizeWindow(int cols, int rows);
|
||||
void scrapeOutput();
|
||||
void freezeConsole();
|
||||
void unfreezeConsole();
|
||||
void syncMarkerText(CHAR_INFO *output);
|
||||
int findSyncMarker();
|
||||
void createSyncMarker(int row);
|
||||
|
||||
private:
|
||||
Win32Console *m_console;
|
||||
NamedPipe *m_controlSocket;
|
||||
NamedPipe *m_dataSocket;
|
||||
bool m_closingDataSocket;
|
||||
Terminal *m_terminal;
|
||||
ConsoleInput *m_consoleInput;
|
||||
HANDLE m_childProcess;
|
||||
int m_childExitCode;
|
||||
|
||||
int m_syncRow;
|
||||
int m_syncCounter;
|
||||
|
||||
int m_scrapedLineCount;
|
||||
int m_scrolledCount;
|
||||
int m_maxBufferedLine;
|
||||
CHAR_INFO (*m_bufferData)[MAX_CONSOLE_WIDTH];
|
||||
int m_dirtyWindowTop;
|
||||
int m_dirtyLineCount;
|
||||
};
|
||||
|
||||
#endif // AGENT_H
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2015 Ryan Prichard
|
||||
// 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
|
||||
@ -18,14 +18,18 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef UNIX_ADAPTER_UTIL_H
|
||||
#define UNIX_ADAPTER_UTIL_H
|
||||
|
||||
#include "AgentAssert.h"
|
||||
#include "../shared/DebugClient.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
bool writeAll(int fd, const void *buffer, size_t size);
|
||||
bool writeStr(int fd, const char *str);
|
||||
void selectWrapper(const char *diagName, int nfds, fd_set *readfds);
|
||||
// Calling the standard assert() function does not work in the agent because
|
||||
// the error message would be printed to the console, and the only way the
|
||||
// user can see the console is via a working agent! This custom assert
|
||||
// function instead sends the message to the DebugServer.
|
||||
|
||||
#endif // UNIX_ADAPTER_UTIL_H
|
||||
void assertFail(const char *file, int line, const char *cond)
|
||||
{
|
||||
trace("Assertion failed: %s, file %s, line %d",
|
||||
cond, file, line);
|
||||
abort();
|
||||
}
|
12
src/libwinpty/AgentLocation.h → agent/AgentAssert.h
Executable file → Normal file
12
src/libwinpty/AgentLocation.h → agent/AgentAssert.h
Executable file → Normal file
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011-2016 Ryan Prichard
|
||||
// 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
|
||||
@ -18,11 +18,11 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LIBWINPTY_AGENT_LOCATION_H
|
||||
#define LIBWINPTY_AGENT_LOCATION_H
|
||||
#ifndef AGENTASSERT_H
|
||||
#define AGENTASSERT_H
|
||||
|
||||
#include <string>
|
||||
#define ASSERT(x) do { if (!(x)) assertFail(__FILE__, __LINE__, #x); } while(0)
|
||||
|
||||
std::wstring findAgentProgram();
|
||||
void assertFail(const char *file, int line, const char *cond);
|
||||
|
||||
#endif // LIBWINPTY_AGENT_LOCATION_H
|
||||
#endif // AGENTASSERT_H
|
485
agent/ConsoleInput.cc
Normal file
485
agent/ConsoleInput.cc
Normal file
@ -0,0 +1,485 @@
|
||||
// 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.
|
||||
|
||||
#include "ConsoleInput.h"
|
||||
#include "Win32Console.h"
|
||||
#include "DsrSender.h"
|
||||
#include "../shared/DebugClient.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef MAPVK_VK_TO_VSC
|
||||
#define MAPVK_VK_TO_VSC 0
|
||||
#endif
|
||||
|
||||
const int kIncompleteEscapeTimeoutMs = 1000;
|
||||
|
||||
#define ESC "\x1B"
|
||||
#define CSI ESC"["
|
||||
#define DIM(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
ConsoleInput::KeyDescriptor ConsoleInput::keyDescriptorTable[] = {
|
||||
// Ctrl-<letter/digit> seems to be handled OK by the default code path.
|
||||
// TODO: Alt-ESC is encoded as ESC ESC. Can it be handled?
|
||||
|
||||
{ ESC, VK_ESCAPE, '\x1B', 0, },
|
||||
|
||||
// Alt-<letter/digit>
|
||||
{ ESC"O", 'O', 0, LEFT_ALT_PRESSED },
|
||||
{ ESC"[", '[', 0, LEFT_ALT_PRESSED },
|
||||
|
||||
// F1-F4 function keys. F5-F12 seem to be handled more consistently among
|
||||
// various TERM=xterm terminals (gnome-terminal, konsole, xterm, mintty),
|
||||
// using a CSI-prefix with an optional extra modifier digit. (putty is
|
||||
// also TERM=xterm, though, and has completely different modified F5-F12
|
||||
// encodings.)
|
||||
{ ESC"OP", VK_F1, 0, 0, }, // xt gt kon
|
||||
{ ESC"OQ", VK_F2, 0, 0, }, // xt gt kon
|
||||
{ ESC"OR", VK_F3, 0, 0, }, // xt gt kon
|
||||
{ ESC"OS", VK_F4, 0, 0, }, // xt gt kon
|
||||
|
||||
{ "\x7F", VK_BACK, '\x08', 0, },
|
||||
{ ESC"\x7F", VK_BACK, '\x08', LEFT_ALT_PRESSED, },
|
||||
{ ESC"OH", VK_HOME, 0, 0, }, // gnome-terminal
|
||||
{ ESC"OF", VK_END, 0, 0, }, // gnome-terminal
|
||||
};
|
||||
|
||||
ConsoleInput::ConsoleInput(Win32Console *console, DsrSender *dsrSender) :
|
||||
m_console(console),
|
||||
m_dsrSender(dsrSender),
|
||||
m_dsrSent(false),
|
||||
lastWriteTick(0)
|
||||
{
|
||||
// Generate CSI encodings and add them to the table.
|
||||
struct CsiEncoding {
|
||||
int id;
|
||||
char letter;
|
||||
int virtualKey;
|
||||
};
|
||||
static const CsiEncoding csiEncodings[] = {
|
||||
{ 0, 'A', VK_UP },
|
||||
{ 0, 'B', VK_DOWN },
|
||||
{ 0, 'C', VK_RIGHT },
|
||||
{ 0, 'D', VK_LEFT },
|
||||
{ 0, 'E', VK_NUMPAD5 },
|
||||
{ 0, 'F', VK_END },
|
||||
{ 0, 'H', VK_HOME },
|
||||
{ 0, 'P', VK_F1 }, // mod+F1 for xterm and mintty
|
||||
{ 0, 'Q', VK_F2 }, // mod+F2 for xterm and mintty
|
||||
{ 0, 'R', VK_F3 }, // mod+F3 for xterm and mintty
|
||||
{ 0, 'S', VK_F4 }, // mod+F4 for xterm and mintty
|
||||
{ 1, '~', VK_HOME },
|
||||
{ 2, '~', VK_INSERT },
|
||||
{ 3, '~', VK_DELETE },
|
||||
{ 4, '~', VK_END }, // gnome-terminal keypad home/end
|
||||
{ 5, '~', VK_PRIOR },
|
||||
{ 6, '~', VK_NEXT },
|
||||
{ 7, '~', VK_HOME },
|
||||
{ 8, '~', VK_END },
|
||||
{ 15, '~', VK_F5 },
|
||||
{ 17, '~', VK_F6 },
|
||||
{ 18, '~', VK_F7 },
|
||||
{ 19, '~', VK_F8 },
|
||||
{ 20, '~', VK_F9 },
|
||||
{ 21, '~', VK_F10 },
|
||||
{ 23, '~', VK_F11 },
|
||||
{ 24, '~', VK_F12 },
|
||||
};
|
||||
const int kCsiShiftModifier = 1;
|
||||
const int kCsiAltModifier = 2;
|
||||
const int kCsiCtrlModifier = 4;
|
||||
char encoding[32];
|
||||
for (size_t i = 0; i < DIM(csiEncodings); ++i) {
|
||||
const CsiEncoding *e = &csiEncodings[i];
|
||||
if (e->id == 0)
|
||||
sprintf(encoding, CSI"%c", e->letter);
|
||||
else
|
||||
sprintf(encoding, CSI"%d%c", e->id, e->letter);
|
||||
KeyDescriptor *k = new KeyDescriptor;
|
||||
k->encoding = NULL;
|
||||
k->encodingLen = strlen(encoding);
|
||||
k->keyState = 0;
|
||||
k->unicodeChar = 0;
|
||||
k->virtualKey = csiEncodings[i].virtualKey;
|
||||
m_lookup.set(encoding, k);
|
||||
int id = !e->id ? 1 : e->id;
|
||||
for (int mod = 2; mod <= 8; ++mod) {
|
||||
sprintf(encoding, CSI"%d;%d%c", id, mod, e->letter);
|
||||
KeyDescriptor *k2 = new KeyDescriptor;
|
||||
*k2 = *k;
|
||||
k2->encodingLen = strlen(encoding);
|
||||
if ((mod - 1) & kCsiShiftModifier) k2->keyState |= SHIFT_PRESSED;
|
||||
if ((mod - 1) & kCsiAltModifier) k2->keyState |= LEFT_ALT_PRESSED;
|
||||
if ((mod - 1) & kCsiCtrlModifier) k2->keyState |= LEFT_CTRL_PRESSED;
|
||||
m_lookup.set(encoding, k2);
|
||||
}
|
||||
}
|
||||
|
||||
// Modified F1-F4 on gnome-terminal and konsole.
|
||||
for (int mod = 2; mod <= 8; ++mod) {
|
||||
for (int fn = 0; fn < 4; ++fn) {
|
||||
for (int fmt = 0; fmt < 1; ++fmt) {
|
||||
if (fmt == 0) {
|
||||
// gnome-terminal
|
||||
sprintf(encoding, ESC"O1;%d%c", mod, 'P' + fn);
|
||||
} else {
|
||||
// konsole
|
||||
sprintf(encoding, ESC"O%d%c", mod, 'P' + fn);
|
||||
}
|
||||
KeyDescriptor *k = new KeyDescriptor;
|
||||
k->encoding = NULL;
|
||||
k->encodingLen = strlen(encoding);
|
||||
k->keyState = 0;
|
||||
if ((mod - 1) & kCsiShiftModifier) k->keyState |= SHIFT_PRESSED;
|
||||
if ((mod - 1) & kCsiAltModifier) k->keyState |= LEFT_ALT_PRESSED;
|
||||
if ((mod - 1) & kCsiCtrlModifier) k->keyState |= LEFT_CTRL_PRESSED;
|
||||
k->unicodeChar = 0;
|
||||
k->virtualKey = VK_F1 + fn;
|
||||
m_lookup.set(encoding, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Static key encodings.
|
||||
for (size_t i = 0; i < sizeof(keyDescriptorTable) / sizeof(keyDescriptorTable[0]); ++i) {
|
||||
KeyDescriptor *k = new KeyDescriptor;
|
||||
*k = keyDescriptorTable[i];
|
||||
k->encodingLen = strlen(k->encoding);
|
||||
m_lookup.set(k->encoding, k);
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleInput::writeInput(const std::string &input)
|
||||
{
|
||||
trace("writeInput: %d bytes", input.size());
|
||||
if (input.size() == 0)
|
||||
return;
|
||||
m_byteQueue.append(input);
|
||||
doWrite(false);
|
||||
if (!m_byteQueue.empty() && !m_dsrSent) {
|
||||
trace("send DSR");
|
||||
m_dsrSender->sendDsr();
|
||||
m_dsrSent = true;
|
||||
}
|
||||
lastWriteTick = GetTickCount();
|
||||
}
|
||||
|
||||
void ConsoleInput::flushIncompleteEscapeCode()
|
||||
{
|
||||
if (!m_byteQueue.empty() &&
|
||||
(int)(GetTickCount() - lastWriteTick) > kIncompleteEscapeTimeoutMs) {
|
||||
doWrite(true);
|
||||
m_byteQueue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleInput::KeyLookup::KeyLookup() : match(NULL), children(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
ConsoleInput::KeyLookup::~KeyLookup()
|
||||
{
|
||||
delete match;
|
||||
if (children != NULL) {
|
||||
for (int i = 0; i < 256; ++i)
|
||||
delete (*children)[i];
|
||||
}
|
||||
delete [] children;
|
||||
}
|
||||
|
||||
void ConsoleInput::KeyLookup::set(const char *encoding,
|
||||
const KeyDescriptor *descriptor)
|
||||
{
|
||||
unsigned char ch = encoding[0];
|
||||
if (ch == '\0') {
|
||||
match = descriptor;
|
||||
return;
|
||||
}
|
||||
if (children == NULL) {
|
||||
children = (KeyLookup*(*)[256])new KeyLookup*[256];
|
||||
memset(children, 0, sizeof(KeyLookup*) * 256);
|
||||
}
|
||||
if ((*children)[ch] == NULL) {
|
||||
(*children)[ch] = new KeyLookup;
|
||||
}
|
||||
(*children)[ch]->set(encoding + 1, descriptor);
|
||||
}
|
||||
|
||||
void ConsoleInput::doWrite(bool isEof)
|
||||
{
|
||||
const char *data = m_byteQueue.c_str();
|
||||
std::vector<INPUT_RECORD> records;
|
||||
size_t idx = 0;
|
||||
while (idx < m_byteQueue.size()) {
|
||||
int charSize = scanKeyPress(records, &data[idx], m_byteQueue.size() - idx, isEof);
|
||||
if (charSize == -1)
|
||||
break;
|
||||
idx += charSize;
|
||||
}
|
||||
m_byteQueue.erase(0, idx);
|
||||
m_console->writeInput(records.data(), records.size());
|
||||
}
|
||||
|
||||
int ConsoleInput::scanKeyPress(std::vector<INPUT_RECORD> &records,
|
||||
const char *input,
|
||||
int inputSize,
|
||||
bool isEof)
|
||||
{
|
||||
trace("scanKeyPress: %d bytes", inputSize);
|
||||
|
||||
// Ctrl-C.
|
||||
if (input[0] == '\x03' && m_console->processedInputMode()) {
|
||||
trace("Ctrl-C");
|
||||
BOOL ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
||||
trace("GenerateConsoleCtrlEvent: %d", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Attempt to match the Device Status Report (DSR) reply.
|
||||
int dsrLen = matchDsr(input);
|
||||
if (dsrLen > 0) {
|
||||
trace("Received a DSR reply");
|
||||
m_dsrSent = false;
|
||||
return dsrLen;
|
||||
} else if (!isEof && dsrLen == -1) {
|
||||
// Incomplete DSR match.
|
||||
trace("Incomplete DSR match");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Recognize Alt-<character>.
|
||||
if (input[0] == '\x1B' &&
|
||||
input[1] != '\0' &&
|
||||
input[1] != '\x1B' &&
|
||||
m_lookup.getChild('\x1B')->getChild(input[1]) == NULL) {
|
||||
int len = utf8CharLength(input[1]);
|
||||
if (1 + len > inputSize) {
|
||||
// Incomplete character.
|
||||
trace("Incomplete Alt-char match");
|
||||
return -1;
|
||||
}
|
||||
appendUtf8Char(records, &input[1], len, LEFT_ALT_PRESSED);
|
||||
return 1 + len;
|
||||
}
|
||||
|
||||
// Recognize an ESC-encoded keypress.
|
||||
bool incomplete;
|
||||
const KeyDescriptor *match = lookupKey(input, isEof, &incomplete);
|
||||
if (incomplete) {
|
||||
// Incomplete match -- need more characters (or wait for a
|
||||
// timeout to signify flushed input).
|
||||
trace("Incomplete ESC-keypress match");
|
||||
return -1;
|
||||
} else if (match != NULL) {
|
||||
appendKeyPress(records,
|
||||
match->virtualKey,
|
||||
match->unicodeChar,
|
||||
match->keyState);
|
||||
return match->encodingLen;
|
||||
}
|
||||
|
||||
// A UTF-8 character.
|
||||
int len = utf8CharLength(input[0]);
|
||||
if (len > inputSize) {
|
||||
// Incomplete character.
|
||||
trace("Incomplete UTF-8 character");
|
||||
return -1;
|
||||
}
|
||||
appendUtf8Char(records, &input[0], len, 0);
|
||||
return len;
|
||||
}
|
||||
|
||||
void ConsoleInput::appendUtf8Char(std::vector<INPUT_RECORD> &records,
|
||||
const char *charBuffer,
|
||||
int charLen,
|
||||
int keyState)
|
||||
{
|
||||
WCHAR wideInput[2];
|
||||
int wideLen = MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
charBuffer,
|
||||
charLen,
|
||||
wideInput,
|
||||
sizeof(wideInput) / sizeof(wideInput[0]));
|
||||
// TODO: Characters outside the BMP.
|
||||
if (wideLen != 1)
|
||||
return;
|
||||
|
||||
short charScan = VkKeyScan(wideInput[0]);
|
||||
int virtualKey = 0;
|
||||
if (charScan != -1) {
|
||||
virtualKey = charScan & 0xFF;
|
||||
if (charScan & 0x100)
|
||||
keyState |= SHIFT_PRESSED;
|
||||
else if (charScan & 0x200)
|
||||
keyState |= LEFT_CTRL_PRESSED;
|
||||
else if (charScan & 0x400)
|
||||
keyState |= LEFT_ALT_PRESSED;
|
||||
}
|
||||
appendKeyPress(records, virtualKey, wideInput[0], keyState);
|
||||
}
|
||||
|
||||
void ConsoleInput::appendKeyPress(std::vector<INPUT_RECORD> &records,
|
||||
int virtualKey,
|
||||
int unicodeChar,
|
||||
int keyState)
|
||||
{
|
||||
bool ctrl = keyState & LEFT_CTRL_PRESSED;
|
||||
bool alt = keyState & LEFT_ALT_PRESSED;
|
||||
bool shift = keyState & SHIFT_PRESSED;
|
||||
int stepKeyState = 0;
|
||||
if (ctrl) {
|
||||
stepKeyState |= LEFT_CTRL_PRESSED;
|
||||
appendInputRecord(records, TRUE, VK_CONTROL, 0, stepKeyState);
|
||||
}
|
||||
if (alt) {
|
||||
stepKeyState |= LEFT_ALT_PRESSED;
|
||||
appendInputRecord(records, TRUE, VK_MENU, 0, stepKeyState);
|
||||
}
|
||||
if (shift) {
|
||||
stepKeyState |= SHIFT_PRESSED;
|
||||
appendInputRecord(records, TRUE, VK_SHIFT, 0, stepKeyState);
|
||||
}
|
||||
if (ctrl && alt) {
|
||||
// This behavior seems arbitrary, but it's what I see in the Windows 7
|
||||
// console.
|
||||
unicodeChar = 0;
|
||||
}
|
||||
appendInputRecord(records, TRUE, virtualKey, unicodeChar, stepKeyState);
|
||||
if (alt) {
|
||||
// This behavior seems arbitrary, but it's what I see in the Windows 7
|
||||
// console.
|
||||
unicodeChar = 0;
|
||||
}
|
||||
appendInputRecord(records, FALSE, virtualKey, unicodeChar, stepKeyState);
|
||||
if (shift) {
|
||||
stepKeyState &= ~SHIFT_PRESSED;
|
||||
appendInputRecord(records, FALSE, VK_SHIFT, 0, stepKeyState);
|
||||
}
|
||||
if (alt) {
|
||||
stepKeyState &= ~LEFT_ALT_PRESSED;
|
||||
appendInputRecord(records, FALSE, VK_MENU, 0, stepKeyState);
|
||||
}
|
||||
if (ctrl) {
|
||||
stepKeyState &= ~LEFT_CTRL_PRESSED;
|
||||
appendInputRecord(records, FALSE, VK_CONTROL, 0, stepKeyState);
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleInput::appendInputRecord(std::vector<INPUT_RECORD> &records,
|
||||
BOOL keyDown,
|
||||
int virtualKey,
|
||||
int unicodeChar,
|
||||
int keyState)
|
||||
{
|
||||
INPUT_RECORD ir;
|
||||
memset(&ir, 0, sizeof(ir));
|
||||
ir.EventType = KEY_EVENT;
|
||||
ir.Event.KeyEvent.bKeyDown = keyDown;
|
||||
ir.Event.KeyEvent.wRepeatCount = 1;
|
||||
ir.Event.KeyEvent.wVirtualKeyCode = virtualKey;
|
||||
ir.Event.KeyEvent.wVirtualScanCode =
|
||||
MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
|
||||
ir.Event.KeyEvent.uChar.UnicodeChar = unicodeChar;
|
||||
ir.Event.KeyEvent.dwControlKeyState = keyState;
|
||||
records.push_back(ir);
|
||||
}
|
||||
|
||||
// Return the byte size of a UTF-8 character using the value of the first
|
||||
// byte.
|
||||
int ConsoleInput::utf8CharLength(char firstByte)
|
||||
{
|
||||
// This code would probably be faster if it used __builtin_clz.
|
||||
if ((firstByte & 0x80) == 0) {
|
||||
return 1;
|
||||
} else if ((firstByte & 0xE0) == 0xC0) {
|
||||
return 2;
|
||||
} else if ((firstByte & 0xF0) == 0xE0) {
|
||||
return 3;
|
||||
} else if ((firstByte & 0xF8) == 0xF0) {
|
||||
return 4;
|
||||
} else if ((firstByte & 0xFC) == 0xF8) {
|
||||
return 5;
|
||||
} else if ((firstByte & 0xFE) == 0xFC) {
|
||||
return 6;
|
||||
} else {
|
||||
// Malformed UTF-8.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the longest matching key and node.
|
||||
const ConsoleInput::KeyDescriptor *
|
||||
ConsoleInput::lookupKey(const char *encoding, bool isEof, bool *incomplete)
|
||||
{
|
||||
trace("lookupKey");
|
||||
for (int i = 0; encoding[i] != '\0'; ++i)
|
||||
trace("%d", encoding[i]);
|
||||
|
||||
*incomplete = false;
|
||||
KeyLookup *node = &m_lookup;
|
||||
const KeyDescriptor *longestMatch = NULL;
|
||||
for (int i = 0; encoding[i] != '\0'; ++i) {
|
||||
unsigned char ch = encoding[i];
|
||||
node = node->getChild(ch);
|
||||
trace("ch: %d --> node:%p", ch, node);
|
||||
if (node == NULL) {
|
||||
return longestMatch;
|
||||
} else if (node->getMatch() != NULL) {
|
||||
longestMatch = node->getMatch();
|
||||
}
|
||||
}
|
||||
if (isEof) {
|
||||
return longestMatch;
|
||||
} else if (node->hasChildren()) {
|
||||
*incomplete = true;
|
||||
return NULL;
|
||||
} else {
|
||||
return longestMatch;
|
||||
}
|
||||
}
|
||||
|
||||
// Match the Device Status Report console input: ESC [ nn ; mm R
|
||||
// Returns:
|
||||
// 0 no match
|
||||
// >0 match, returns length of match
|
||||
// -1 incomplete match
|
||||
int ConsoleInput::matchDsr(const char *encoding)
|
||||
{
|
||||
const char *pch = encoding;
|
||||
#define CHECK(cond) \
|
||||
do { \
|
||||
if (cond) { pch++; } \
|
||||
else if (*pch == '\0') { return -1; } \
|
||||
else { return 0; } \
|
||||
} while(0)
|
||||
CHECK(*pch == '\x1B');
|
||||
CHECK(*pch == '[');
|
||||
CHECK(isdigit(*pch));
|
||||
while (isdigit(*pch))
|
||||
pch++;
|
||||
CHECK(*pch == ';');
|
||||
CHECK(isdigit(*pch));
|
||||
while (isdigit(*pch))
|
||||
pch++;
|
||||
CHECK(*pch == 'R');
|
||||
return pch - encoding;
|
||||
#undef CHECK
|
||||
}
|
92
agent/ConsoleInput.h
Normal file
92
agent/ConsoleInput.h
Normal file
@ -0,0 +1,92 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CONSOLEINPUT_H
|
||||
#define CONSOLEINPUT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
||||
class Win32Console;
|
||||
class DsrSender;
|
||||
|
||||
class ConsoleInput
|
||||
{
|
||||
public:
|
||||
ConsoleInput(Win32Console *console, DsrSender *dsrSender);
|
||||
void writeInput(const std::string &input);
|
||||
void flushIncompleteEscapeCode();
|
||||
|
||||
private:
|
||||
struct KeyDescriptor {
|
||||
const char *encoding;
|
||||
int virtualKey;
|
||||
int unicodeChar;
|
||||
int keyState;
|
||||
int encodingLen;
|
||||
};
|
||||
|
||||
class KeyLookup {
|
||||
public:
|
||||
KeyLookup();
|
||||
~KeyLookup();
|
||||
void set(const char *encoding, const KeyDescriptor *descriptor);
|
||||
const KeyDescriptor *getMatch() const { return match; }
|
||||
bool hasChildren() const { return children != NULL; }
|
||||
KeyLookup *getChild(int i) { return children != NULL ? (*children)[i] : NULL; }
|
||||
private:
|
||||
const KeyDescriptor *match;
|
||||
KeyLookup *(*children)[256];
|
||||
};
|
||||
|
||||
void doWrite(bool isEof);
|
||||
int scanKeyPress(std::vector<INPUT_RECORD> &records,
|
||||
const char *input,
|
||||
int inputSize,
|
||||
bool isEof);
|
||||
void appendUtf8Char(std::vector<INPUT_RECORD> &records,
|
||||
const char *charBuffer,
|
||||
int charLen,
|
||||
int keyState);
|
||||
void appendKeyPress(std::vector<INPUT_RECORD> &records,
|
||||
int virtualKey,
|
||||
int unicodeChar,
|
||||
int keyState);
|
||||
void appendInputRecord(std::vector<INPUT_RECORD> &records,
|
||||
BOOL keyDown,
|
||||
int virtualKey,
|
||||
int unicodeChar,
|
||||
int keyState);
|
||||
static int utf8CharLength(char firstByte);
|
||||
const KeyDescriptor *lookupKey(const char *encoding, bool isEof, bool *incomplete);
|
||||
static int matchDsr(const char *encoding);
|
||||
|
||||
private:
|
||||
static KeyDescriptor keyDescriptorTable[];
|
||||
Win32Console *m_console;
|
||||
DsrSender *m_dsrSender;
|
||||
bool m_dsrSent;
|
||||
std::string m_byteQueue;
|
||||
KeyLookup m_lookup;
|
||||
DWORD lastWriteTick;
|
||||
};
|
||||
|
||||
#endif // CONSOLEINPUT_H
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2015 Ryan Prichard
|
||||
// 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
|
||||
@ -18,11 +18,12 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef DEFAULT_INPUT_MAP_H
|
||||
#define DEFAULT_INPUT_MAP_H
|
||||
#include "Coord.h"
|
||||
#include <stdio.h>
|
||||
|
||||
class InputMap;
|
||||
|
||||
void addDefaultEntriesToInputMap(InputMap &inputMap);
|
||||
|
||||
#endif // DEFAULT_INPUT_MAP_H
|
||||
std::string Coord::toString() const
|
||||
{
|
||||
char ret[32];
|
||||
sprintf(ret, "(%d,%d)", X, Y);
|
||||
return std::string(ret);
|
||||
}
|
@ -22,11 +22,8 @@
|
||||
#define COORD_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../shared/winpty_snprintf.h"
|
||||
|
||||
struct Coord : COORD {
|
||||
Coord()
|
||||
{
|
||||
@ -76,12 +73,7 @@ struct Coord : COORD {
|
||||
return X <= 0 || Y <= 0;
|
||||
}
|
||||
|
||||
std::string toString() const
|
||||
{
|
||||
char ret[32];
|
||||
winpty_snprintf(ret, "(%d,%d)", X, Y);
|
||||
return std::string(ret);
|
||||
}
|
||||
std::string toString() const;
|
||||
};
|
||||
|
||||
#endif // COORD_H
|
@ -19,18 +19,18 @@
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#include "EventLoop.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "NamedPipe.h"
|
||||
#include "AgentAssert.h"
|
||||
#include "../shared/DebugClient.h"
|
||||
#include "../shared/WinptyAssert.h"
|
||||
|
||||
EventLoop::~EventLoop() {
|
||||
for (NamedPipe *pipe : m_pipes) {
|
||||
delete pipe;
|
||||
}
|
||||
m_pipes.clear();
|
||||
EventLoop::EventLoop() : m_exiting(false), m_pollInterval(0)
|
||||
{
|
||||
}
|
||||
|
||||
EventLoop::~EventLoop()
|
||||
{
|
||||
for (size_t i = 0; i < m_pipes.size(); ++i)
|
||||
delete m_pipes[i];
|
||||
}
|
||||
|
||||
// Enter the event loop. Runs until the I/O or timeout handler calls exit().
|
||||
@ -45,7 +45,7 @@ void EventLoop::run()
|
||||
waitHandles.clear();
|
||||
for (size_t i = 0; i < m_pipes.size(); ++i) {
|
||||
if (m_pipes[i]->serviceIo(&waitHandles)) {
|
||||
onPipeIo(*m_pipes[i]);
|
||||
onPipeIo(m_pipes[i]);
|
||||
didSomething = true;
|
||||
}
|
||||
}
|
||||
@ -81,11 +81,11 @@ void EventLoop::run()
|
||||
}
|
||||
}
|
||||
|
||||
NamedPipe &EventLoop::createNamedPipe()
|
||||
NamedPipe *EventLoop::createNamedPipe()
|
||||
{
|
||||
NamedPipe *ret = new NamedPipe();
|
||||
m_pipes.push_back(ret);
|
||||
return *ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EventLoop::setPollInterval(int ms)
|
||||
@ -97,3 +97,11 @@ void EventLoop::shutdown()
|
||||
{
|
||||
m_exiting = true;
|
||||
}
|
||||
|
||||
void EventLoop::onPollTimeout()
|
||||
{
|
||||
}
|
||||
|
||||
void EventLoop::onPipeIo(NamedPipe *namedPipe)
|
||||
{
|
||||
}
|
@ -28,20 +28,21 @@ class NamedPipe;
|
||||
class EventLoop
|
||||
{
|
||||
public:
|
||||
EventLoop();
|
||||
virtual ~EventLoop();
|
||||
void run();
|
||||
|
||||
protected:
|
||||
NamedPipe &createNamedPipe();
|
||||
NamedPipe *createNamedPipe();
|
||||
void setPollInterval(int ms);
|
||||
void shutdown();
|
||||
virtual void onPollTimeout() {}
|
||||
virtual void onPipeIo(NamedPipe &namedPipe) {}
|
||||
virtual void onPollTimeout();
|
||||
virtual void onPipeIo(NamedPipe *namedPipe);
|
||||
|
||||
private:
|
||||
bool m_exiting = false;
|
||||
bool m_exiting;
|
||||
std::vector<NamedPipe*> m_pipes;
|
||||
int m_pollInterval = 0;
|
||||
int m_pollInterval;
|
||||
};
|
||||
|
||||
#endif // EVENTLOOP_H
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015 Ryan Prichard
|
||||
# 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
|
||||
@ -18,24 +18,41 @@
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
ALL_TARGETS += build/winpty-debugserver.exe
|
||||
include ../config.mk
|
||||
include ../config-mingw.mk
|
||||
|
||||
$(eval $(call def_mingw_target,debugserver,))
|
||||
PROGRAM = ../build/winpty-agent.exe
|
||||
|
||||
DEBUGSERVER_OBJECTS = \
|
||||
build/debugserver/debugserver/DebugServer.o \
|
||||
build/debugserver/shared/DebugClient.o \
|
||||
build/debugserver/shared/OwnedHandle.o \
|
||||
build/debugserver/shared/StringUtil.o \
|
||||
build/debugserver/shared/WindowsSecurity.o \
|
||||
build/debugserver/shared/WindowsVersion.o \
|
||||
build/debugserver/shared/WinptyAssert.o \
|
||||
build/debugserver/shared/WinptyException.o
|
||||
OBJECTS = \
|
||||
EventLoop.o \
|
||||
NamedPipe.o \
|
||||
Agent.o \
|
||||
AgentAssert.o \
|
||||
Terminal.o \
|
||||
Win32Console.o \
|
||||
ConsoleInput.o \
|
||||
DebugClient.o \
|
||||
Coord.o \
|
||||
SmallRect.o \
|
||||
main.o
|
||||
|
||||
build/debugserver/shared/WindowsVersion.o : build/gen/GenVersion.h
|
||||
CXXFLAGS += \
|
||||
-DUNICODE \
|
||||
-D_UNICODE \
|
||||
-D_WIN32_WINNT=0x0501 \
|
||||
-fno-exceptions \
|
||||
-fno-rtti
|
||||
|
||||
build/winpty-debugserver.exe : $(DEBUGSERVER_OBJECTS)
|
||||
$(info Linking $@)
|
||||
@$(MINGW_CXX) $(MINGW_LDFLAGS) -o $@ $^
|
||||
LDFLAGS += -static-libgcc -static-libstdc++
|
||||
|
||||
-include $(DEBUGSERVER_OBJECTS:.o=.d)
|
||||
all : $(PROGRAM)
|
||||
|
||||
$(PROGRAM) : $(OBJECTS)
|
||||
@echo Linking $@
|
||||
@$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
.PHONY : clean
|
||||
clean:
|
||||
rm -f $(PROGRAM) *.o *.d
|
||||
|
||||
-include $(OBJECTS:.o=.d)
|
258
agent/NamedPipe.cc
Normal file
258
agent/NamedPipe.cc
Normal file
@ -0,0 +1,258 @@
|
||||
// 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.
|
||||
|
||||
#include "NamedPipe.h"
|
||||
#include "EventLoop.h"
|
||||
#include "AgentAssert.h"
|
||||
#include "../shared/DebugClient.h"
|
||||
#include <string.h>
|
||||
|
||||
NamedPipe::NamedPipe() :
|
||||
m_readBufferSize(64 * 1024),
|
||||
m_handle(NULL),
|
||||
m_inputWorker(NULL),
|
||||
m_outputWorker(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
NamedPipe::~NamedPipe()
|
||||
{
|
||||
closePipe();
|
||||
}
|
||||
|
||||
// Returns true if anything happens (data received, data sent, pipe error).
|
||||
bool NamedPipe::serviceIo(std::vector<HANDLE> *waitHandles)
|
||||
{
|
||||
if (m_handle == NULL)
|
||||
return false;
|
||||
int readBytes = m_inputWorker->service();
|
||||
int writeBytes = m_outputWorker->service();
|
||||
if (readBytes == -1 || writeBytes == -1) {
|
||||
closePipe();
|
||||
return true;
|
||||
}
|
||||
if (m_inputWorker->getWaitEvent() != NULL)
|
||||
waitHandles->push_back(m_inputWorker->getWaitEvent());
|
||||
if (m_outputWorker->getWaitEvent() != NULL)
|
||||
waitHandles->push_back(m_outputWorker->getWaitEvent());
|
||||
return readBytes > 0 || writeBytes > 0;
|
||||
}
|
||||
|
||||
NamedPipe::IoWorker::IoWorker(NamedPipe *namedPipe) :
|
||||
m_namedPipe(namedPipe),
|
||||
m_pending(false),
|
||||
m_currentIoSize(-1)
|
||||
{
|
||||
m_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
ASSERT(m_event != NULL);
|
||||
}
|
||||
|
||||
NamedPipe::IoWorker::~IoWorker()
|
||||
{
|
||||
CloseHandle(m_event);
|
||||
}
|
||||
|
||||
int NamedPipe::IoWorker::service()
|
||||
{
|
||||
int progress = 0;
|
||||
if (m_pending) {
|
||||
DWORD actual;
|
||||
BOOL ret = GetOverlappedResult(m_namedPipe->m_handle, &m_over, &actual, FALSE);
|
||||
if (!ret) {
|
||||
if (GetLastError() == ERROR_IO_INCOMPLETE) {
|
||||
// There is a pending I/O.
|
||||
return progress;
|
||||
} else {
|
||||
// Pipe error.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ResetEvent(m_event);
|
||||
m_pending = false;
|
||||
completeIo(actual);
|
||||
m_currentIoSize = -1;
|
||||
progress += actual;
|
||||
}
|
||||
int nextSize;
|
||||
bool isRead;
|
||||
while (shouldIssueIo(&nextSize, &isRead)) {
|
||||
m_currentIoSize = nextSize;
|
||||
DWORD actual = 0;
|
||||
memset(&m_over, 0, sizeof(m_over));
|
||||
m_over.hEvent = m_event;
|
||||
BOOL ret = isRead
|
||||
? ReadFile(m_namedPipe->m_handle, m_buffer, nextSize, &actual, &m_over)
|
||||
: WriteFile(m_namedPipe->m_handle, m_buffer, nextSize, &actual, &m_over);
|
||||
if (!ret) {
|
||||
if (GetLastError() == ERROR_IO_PENDING) {
|
||||
// There is a pending I/O.
|
||||
m_pending = true;
|
||||
return progress;
|
||||
} else {
|
||||
// Pipe error.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ResetEvent(m_event);
|
||||
completeIo(actual);
|
||||
m_currentIoSize = -1;
|
||||
progress += actual;
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
HANDLE NamedPipe::IoWorker::getWaitEvent()
|
||||
{
|
||||
return m_pending ? m_event : NULL;
|
||||
}
|
||||
|
||||
void NamedPipe::InputWorker::completeIo(int size)
|
||||
{
|
||||
m_namedPipe->m_inQueue.append(m_buffer, size);
|
||||
}
|
||||
|
||||
bool NamedPipe::InputWorker::shouldIssueIo(int *size, bool *isRead)
|
||||
{
|
||||
*isRead = true;
|
||||
if (m_namedPipe->isClosed()) {
|
||||
return false;
|
||||
} else if ((int)m_namedPipe->m_inQueue.size() < m_namedPipe->readBufferSize()) {
|
||||
*size = kIoSize;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void NamedPipe::OutputWorker::completeIo(int size)
|
||||
{
|
||||
ASSERT(size == m_currentIoSize);
|
||||
}
|
||||
|
||||
bool NamedPipe::OutputWorker::shouldIssueIo(int *size, bool *isRead)
|
||||
{
|
||||
*isRead = false;
|
||||
if (!m_namedPipe->m_outQueue.empty()) {
|
||||
int writeSize = std::min((int)m_namedPipe->m_outQueue.size(), (int)kIoSize);
|
||||
memcpy(m_buffer, m_namedPipe->m_outQueue.data(), writeSize);
|
||||
m_namedPipe->m_outQueue.erase(0, writeSize);
|
||||
*size = writeSize;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int NamedPipe::OutputWorker::getPendingIoSize()
|
||||
{
|
||||
return m_pending ? m_currentIoSize : 0;
|
||||
}
|
||||
|
||||
bool NamedPipe::connectToServer(LPCWSTR pipeName)
|
||||
{
|
||||
ASSERT(isClosed());
|
||||
HANDLE handle = CreateFile(pipeName,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
trace("connection to [%ls], handle == 0x%x", pipeName, handle);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
m_handle = handle;
|
||||
m_inputWorker = new InputWorker(this);
|
||||
m_outputWorker = new OutputWorker(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
int NamedPipe::bytesToSend()
|
||||
{
|
||||
int ret = m_outQueue.size();
|
||||
if (m_outputWorker != NULL)
|
||||
ret += m_outputWorker->getPendingIoSize();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void NamedPipe::write(const void *data, int size)
|
||||
{
|
||||
m_outQueue.append((const char*)data, size);
|
||||
}
|
||||
|
||||
void NamedPipe::write(const char *text)
|
||||
{
|
||||
write(text, strlen(text));
|
||||
}
|
||||
|
||||
int NamedPipe::readBufferSize()
|
||||
{
|
||||
return m_readBufferSize;
|
||||
}
|
||||
|
||||
void NamedPipe::setReadBufferSize(int size)
|
||||
{
|
||||
m_readBufferSize = size;
|
||||
}
|
||||
|
||||
int NamedPipe::bytesAvailable()
|
||||
{
|
||||
return m_inQueue.size();
|
||||
}
|
||||
|
||||
int NamedPipe::peek(void *data, int size)
|
||||
{
|
||||
int ret = std::min(size, (int)m_inQueue.size());
|
||||
memcpy(data, m_inQueue.data(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NamedPipe::read(int size)
|
||||
{
|
||||
int retSize = std::min(size, (int)m_inQueue.size());
|
||||
std::string ret = m_inQueue.substr(0, retSize);
|
||||
m_inQueue.erase(0, retSize);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NamedPipe::readAll()
|
||||
{
|
||||
std::string ret = m_inQueue;
|
||||
m_inQueue.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void NamedPipe::closePipe()
|
||||
{
|
||||
if (m_handle == NULL)
|
||||
return;
|
||||
CancelIo(m_handle);
|
||||
delete m_inputWorker;
|
||||
delete m_outputWorker;
|
||||
CloseHandle(m_handle);
|
||||
m_handle = NULL;
|
||||
m_inputWorker = NULL;
|
||||
m_outputWorker = NULL;
|
||||
}
|
||||
|
||||
bool NamedPipe::isClosed()
|
||||
{
|
||||
return m_handle == NULL;
|
||||
}
|
103
agent/NamedPipe.h
Normal file
103
agent/NamedPipe.h
Normal file
@ -0,0 +1,103 @@
|
||||
// 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.
|
||||
|
||||
#ifndef NAMEDPIPE_H
|
||||
#define NAMEDPIPE_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
class EventLoop;
|
||||
|
||||
class NamedPipe
|
||||
{
|
||||
private:
|
||||
// The EventLoop uses these private members.
|
||||
friend class EventLoop;
|
||||
NamedPipe();
|
||||
~NamedPipe();
|
||||
bool serviceIo(std::vector<HANDLE> *waitHandles);
|
||||
|
||||
private:
|
||||
class IoWorker
|
||||
{
|
||||
public:
|
||||
IoWorker(NamedPipe *namedPipe);
|
||||
virtual ~IoWorker();
|
||||
int service();
|
||||
HANDLE getWaitEvent();
|
||||
protected:
|
||||
NamedPipe *m_namedPipe;
|
||||
bool m_pending;
|
||||
int m_currentIoSize;
|
||||
HANDLE m_event;
|
||||
OVERLAPPED m_over;
|
||||
enum { kIoSize = 64 * 1024 };
|
||||
char m_buffer[kIoSize];
|
||||
virtual void completeIo(int size) = 0;
|
||||
virtual bool shouldIssueIo(int *size, bool *isRead) = 0;
|
||||
};
|
||||
|
||||
class InputWorker : public IoWorker
|
||||
{
|
||||
public:
|
||||
InputWorker(NamedPipe *namedPipe) : IoWorker(namedPipe) {}
|
||||
protected:
|
||||
virtual void completeIo(int size);
|
||||
virtual bool shouldIssueIo(int *size, bool *isRead);
|
||||
};
|
||||
|
||||
class OutputWorker : public IoWorker
|
||||
{
|
||||
public:
|
||||
OutputWorker(NamedPipe *namedPipe) : IoWorker(namedPipe) {}
|
||||
int getPendingIoSize();
|
||||
protected:
|
||||
virtual void completeIo(int size);
|
||||
virtual bool shouldIssueIo(int *size, bool *isRead);
|
||||
};
|
||||
|
||||
public:
|
||||
bool connectToServer(LPCWSTR pipeName);
|
||||
int bytesToSend();
|
||||
void write(const void *data, int size);
|
||||
void write(const char *text);
|
||||
int readBufferSize();
|
||||
void setReadBufferSize(int size);
|
||||
int bytesAvailable();
|
||||
int peek(void *data, int size);
|
||||
std::string read(int size);
|
||||
std::string readAll();
|
||||
void closePipe();
|
||||
bool isClosed();
|
||||
|
||||
private:
|
||||
// Input/output buffers
|
||||
int m_readBufferSize;
|
||||
std::string m_inQueue;
|
||||
std::string m_outQueue;
|
||||
HANDLE m_handle;
|
||||
InputWorker *m_inputWorker;
|
||||
OutputWorker *m_outputWorker;
|
||||
};
|
||||
|
||||
#endif // NAMEDPIPE_H
|
18
src/agent/AgentCreateDesktop.h → agent/SmallRect.cc
Executable file → Normal file
18
src/agent/AgentCreateDesktop.h → agent/SmallRect.cc
Executable file → Normal file
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2016 Ryan Prichard
|
||||
// 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
|
||||
@ -18,11 +18,13 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef AGENT_CREATE_DESKTOP_H
|
||||
#define AGENT_CREATE_DESKTOP_H
|
||||
#include "SmallRect.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
void handleCreateDesktop(LPCWSTR controlPipeName);
|
||||
|
||||
#endif // AGENT_CREATE_DESKTOP_H
|
||||
std::string SmallRect::toString() const
|
||||
{
|
||||
char ret[64];
|
||||
sprintf(ret, "(x=%d,y=%d,w=%d,h=%d)",
|
||||
Left, Top, width(), height());
|
||||
return std::string(ret);
|
||||
}
|
@ -22,13 +22,10 @@
|
||||
#define SMALLRECT_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "Coord.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "../shared/winpty_snprintf.h"
|
||||
#include "Coord.h"
|
||||
|
||||
struct SmallRect : SMALL_RECT
|
||||
{
|
||||
SmallRect()
|
||||
@ -76,14 +73,6 @@ struct SmallRect : SMALL_RECT
|
||||
other.Bottom <= Bottom;
|
||||
}
|
||||
|
||||
bool contains(const Coord &other) const
|
||||
{
|
||||
return other.X >= Left &&
|
||||
other.X <= Right &&
|
||||
other.Y >= Top &&
|
||||
other.Y <= Bottom;
|
||||
}
|
||||
|
||||
SmallRect intersected(const SmallRect &other) const
|
||||
{
|
||||
int x1 = std::max(Left, other.Left);
|
||||
@ -96,18 +85,6 @@ struct SmallRect : SMALL_RECT
|
||||
std::max(0, y2 - y1 + 1));
|
||||
}
|
||||
|
||||
SmallRect ensureLineIncluded(SHORT line) const
|
||||
{
|
||||
const SHORT h = height();
|
||||
if (line < Top) {
|
||||
return SmallRect(Left, line, width(), h);
|
||||
} else if (line > Bottom) {
|
||||
return SmallRect(Left, line - h + 1, width(), h);
|
||||
} else {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
SHORT top() const { return Top; }
|
||||
SHORT left() const { return Left; }
|
||||
SHORT width() const { return Right - Left + 1; }
|
||||
@ -131,13 +108,7 @@ struct SmallRect : SMALL_RECT
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
std::string toString() const
|
||||
{
|
||||
char ret[64];
|
||||
winpty_snprintf(ret, "(x=%d,y=%d,w=%d,h=%d)",
|
||||
Left, Top, width(), height());
|
||||
return std::string(ret);
|
||||
}
|
||||
std::string toString() const;
|
||||
};
|
||||
|
||||
#endif // SMALLRECT_H
|
201
agent/Terminal.cc
Normal file
201
agent/Terminal.cc
Normal file
@ -0,0 +1,201 @@
|
||||
// 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.
|
||||
|
||||
#include "Terminal.h"
|
||||
#include "NamedPipe.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#define CSI "\x1b["
|
||||
|
||||
const int COLOR_ATTRIBUTE_MASK =
|
||||
FOREGROUND_BLUE |
|
||||
FOREGROUND_GREEN |
|
||||
FOREGROUND_RED |
|
||||
FOREGROUND_INTENSITY |
|
||||
BACKGROUND_BLUE |
|
||||
BACKGROUND_GREEN |
|
||||
BACKGROUND_RED |
|
||||
BACKGROUND_INTENSITY;
|
||||
|
||||
const int TERMINAL_BLACK = 0;
|
||||
const int TERMINAL_RED = 1;
|
||||
const int TERMINAL_GREEN = 2;
|
||||
const int TERMINAL_BLUE = 4;
|
||||
const int TERMINAL_WHITE = 7;
|
||||
|
||||
const int TERMINAL_FOREGROUND = 30;
|
||||
const int TERMINAL_BACKGROUND = 40;
|
||||
|
||||
Terminal::Terminal(NamedPipe *output) :
|
||||
m_output(output),
|
||||
m_remoteLine(0),
|
||||
m_cursorHidden(false),
|
||||
m_remoteColor(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void Terminal::reset(bool sendClearFirst, int newLine)
|
||||
{
|
||||
if (sendClearFirst)
|
||||
m_output->write(CSI"1;1H" CSI"2J");
|
||||
m_remoteLine = newLine;
|
||||
m_cursorHidden = false;
|
||||
m_cursorPos = std::pair<int, int>(0, newLine);
|
||||
m_remoteColor = -1;
|
||||
}
|
||||
|
||||
void Terminal::sendLine(int line, CHAR_INFO *lineData, int width)
|
||||
{
|
||||
hideTerminalCursor();
|
||||
moveTerminalToLine(line);
|
||||
|
||||
// Erase in Line -- erase entire line.
|
||||
m_output->write(CSI"2K");
|
||||
|
||||
std::string termLine;
|
||||
termLine.reserve(width + 32);
|
||||
|
||||
int length = 0;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
int color = lineData[i].Attributes & COLOR_ATTRIBUTE_MASK;
|
||||
if (color != m_remoteColor) {
|
||||
int fore = 0;
|
||||
int back = 0;
|
||||
if (color & FOREGROUND_RED) fore |= TERMINAL_RED;
|
||||
if (color & FOREGROUND_GREEN) fore |= TERMINAL_GREEN;
|
||||
if (color & FOREGROUND_BLUE) fore |= TERMINAL_BLUE;
|
||||
if (color & BACKGROUND_RED) back |= TERMINAL_RED;
|
||||
if (color & BACKGROUND_GREEN) back |= TERMINAL_GREEN;
|
||||
if (color & BACKGROUND_BLUE) back |= TERMINAL_BLUE;
|
||||
|
||||
char buffer[128];
|
||||
if (back == TERMINAL_BLACK) {
|
||||
if (fore == TERMINAL_WHITE) {
|
||||
// Use the terminal's default colors.
|
||||
sprintf(buffer, CSI"0");
|
||||
} else if (fore == TERMINAL_BLACK) {
|
||||
// Attempt to hide the character, but some terminals won't
|
||||
// hide it. Is this an important case?
|
||||
sprintf(buffer, CSI"0;8");
|
||||
} else {
|
||||
sprintf(buffer, CSI"0;%d", TERMINAL_FOREGROUND + fore);
|
||||
}
|
||||
if (color & FOREGROUND_INTENSITY)
|
||||
strcat(buffer, ";1");
|
||||
} else if (back == TERMINAL_WHITE) {
|
||||
// Use the terminal's inverted colors.
|
||||
if (fore == TERMINAL_BLACK) {
|
||||
sprintf(buffer, CSI"0;7");
|
||||
} else if (fore == TERMINAL_WHITE) {
|
||||
// Attempt to hide the character, but some terminals won't
|
||||
// hide it. Is this an important case?
|
||||
sprintf(buffer, CSI"0;7;8");
|
||||
} else {
|
||||
sprintf(buffer, CSI"0;7;%d", TERMINAL_BACKGROUND + fore);
|
||||
}
|
||||
// Don't worry about FOREGROUND_INTENSITY because with at least
|
||||
// one terminal (gnome-terminal 2.32.0), setting the Intensity
|
||||
// flag affects both foreground and background when Reverse
|
||||
// flag is also set.
|
||||
} else {
|
||||
sprintf(buffer, CSI"0;%d;%d",
|
||||
TERMINAL_FOREGROUND + fore,
|
||||
TERMINAL_BACKGROUND + back);
|
||||
if (color & FOREGROUND_INTENSITY)
|
||||
strcat(buffer, ";1");
|
||||
}
|
||||
strcat(buffer, "m");
|
||||
termLine.append(buffer);
|
||||
length = termLine.size();
|
||||
m_remoteColor = color;
|
||||
}
|
||||
// TODO: Is it inefficient to call WideCharToMultiByte once per
|
||||
// character?
|
||||
char mbstr[16];
|
||||
int mblen = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
&lineData[i].Char.UnicodeChar,
|
||||
1,
|
||||
mbstr,
|
||||
sizeof(mbstr),
|
||||
NULL,
|
||||
NULL);
|
||||
if (mblen <= 0) {
|
||||
mbstr[0] = '?';
|
||||
mblen = 1;
|
||||
}
|
||||
if (mblen == 1 && mbstr[0] == ' ') {
|
||||
termLine.push_back(' ');
|
||||
} else {
|
||||
termLine.append(mbstr, mblen);
|
||||
length = termLine.size();
|
||||
}
|
||||
}
|
||||
|
||||
m_output->write(termLine.data(), length);
|
||||
}
|
||||
|
||||
void Terminal::finishOutput(const std::pair<int, int> &newCursorPos)
|
||||
{
|
||||
if (newCursorPos != m_cursorPos)
|
||||
hideTerminalCursor();
|
||||
if (m_cursorHidden) {
|
||||
moveTerminalToLine(newCursorPos.second);
|
||||
char buffer[32];
|
||||
sprintf(buffer, CSI"%dG" CSI"?25h", newCursorPos.first + 1);
|
||||
m_output->write(buffer);
|
||||
m_cursorHidden = false;
|
||||
}
|
||||
m_cursorPos = newCursorPos;
|
||||
}
|
||||
|
||||
void Terminal::hideTerminalCursor()
|
||||
{
|
||||
if (m_cursorHidden)
|
||||
return;
|
||||
m_output->write(CSI"?25l");
|
||||
m_cursorHidden = true;
|
||||
}
|
||||
|
||||
void Terminal::moveTerminalToLine(int line)
|
||||
{
|
||||
// Do not use CPL or CNL. Konsole 2.5.4 does not support Cursor Previous
|
||||
// Line (CPL) -- there are "Undecodable sequence" errors. gnome-terminal
|
||||
// 2.32.0 does handle it. Cursor Next Line (CNL) does nothing if the
|
||||
// cursor is on the last line already.
|
||||
|
||||
if (line < m_remoteLine) {
|
||||
// CUrsor Up (CUU)
|
||||
char buffer[32];
|
||||
sprintf(buffer, "\r" CSI"%dA", m_remoteLine - line);
|
||||
m_output->write(buffer);
|
||||
m_remoteLine = line;
|
||||
} else if (line > m_remoteLine) {
|
||||
while (line > m_remoteLine) {
|
||||
m_output->write("\r\n");
|
||||
m_remoteLine++;
|
||||
}
|
||||
} else {
|
||||
m_output->write("\r");
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2015 Ryan Prichard
|
||||
// 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
|
||||
@ -18,24 +18,33 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef CONSOLE_LINE_H
|
||||
#define CONSOLE_LINE_H
|
||||
#ifndef TERMINAL_H
|
||||
#define TERMINAL_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "Coord.h"
|
||||
#include <utility>
|
||||
|
||||
#include <vector>
|
||||
class NamedPipe;
|
||||
|
||||
class ConsoleLine
|
||||
class Terminal
|
||||
{
|
||||
public:
|
||||
ConsoleLine();
|
||||
void reset();
|
||||
bool detectChangeAndSetLine(const CHAR_INFO *line, int newLength);
|
||||
void setLine(const CHAR_INFO *line, int newLength);
|
||||
void blank(WORD attributes);
|
||||
explicit Terminal(NamedPipe *output);
|
||||
void reset(bool sendClearFirst, int newLine);
|
||||
void sendLine(int line, CHAR_INFO *lineData, int width);
|
||||
void finishOutput(const std::pair<int, int> &newCursorPos);
|
||||
|
||||
private:
|
||||
int m_prevLength;
|
||||
std::vector<CHAR_INFO> m_prevData;
|
||||
void hideTerminalCursor();
|
||||
void moveTerminalToLine(int line);
|
||||
|
||||
private:
|
||||
NamedPipe *m_output;
|
||||
int m_remoteLine;
|
||||
bool m_cursorHidden;
|
||||
std::pair<int, int> m_cursorPos;
|
||||
int m_remoteColor;
|
||||
};
|
||||
|
||||
#endif // CONSOLE_LINE_H
|
||||
#endif // TERMINAL_H
|
299
agent/Win32Console.cc
Normal file
299
agent/Win32Console.cc
Normal file
@ -0,0 +1,299 @@
|
||||
// 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.
|
||||
|
||||
#include "Win32Console.h"
|
||||
#include "AgentAssert.h"
|
||||
#include "../shared/DebugClient.h"
|
||||
#include <windows.h>
|
||||
|
||||
Win32Console::Win32Console()
|
||||
{
|
||||
m_conin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
m_conout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
}
|
||||
|
||||
Win32Console::~Win32Console()
|
||||
{
|
||||
CloseHandle(m_conin);
|
||||
CloseHandle(m_conout);
|
||||
}
|
||||
|
||||
HANDLE Win32Console::conin()
|
||||
{
|
||||
return m_conin;
|
||||
}
|
||||
|
||||
HANDLE Win32Console::conout()
|
||||
{
|
||||
return m_conout;
|
||||
}
|
||||
|
||||
HWND Win32Console::hwnd()
|
||||
{
|
||||
return GetConsoleWindow();
|
||||
}
|
||||
|
||||
void Win32Console::postCloseMessage()
|
||||
{
|
||||
HWND h = hwnd();
|
||||
if (h != NULL)
|
||||
PostMessage(h, WM_CLOSE, 0, 0);
|
||||
}
|
||||
|
||||
// A Windows console window can never be larger than the desktop window. To
|
||||
// maximize the possible size of the console in rows*cols, try to configure
|
||||
// the console with a small font.
|
||||
void Win32Console::setSmallFont()
|
||||
{
|
||||
// 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];
|
||||
};
|
||||
|
||||
typedef BOOL WINAPI SetConsoleFontType(
|
||||
HANDLE hOutput,
|
||||
DWORD dwFontIndex);
|
||||
typedef BOOL WINAPI GetCurrentConsoleFontType(
|
||||
HANDLE hOutput,
|
||||
BOOL bMaximize,
|
||||
AGENT_CONSOLE_FONT_INFO *pFontInfo);
|
||||
typedef BOOL WINAPI SetCurrentConsoleFontExType(
|
||||
HANDLE hConsoleOutput,
|
||||
BOOL bMaximumWindow,
|
||||
AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
|
||||
typedef COORD WINAPI GetConsoleFontSizeType(
|
||||
HANDLE hConsoleOutput,
|
||||
DWORD nFont);
|
||||
|
||||
HINSTANCE dll = LoadLibrary(L"kernel32.dll");
|
||||
ASSERT(dll != NULL);
|
||||
|
||||
SetConsoleFontType *pSetConsoleFont =
|
||||
(SetConsoleFontType*)GetProcAddress(dll, "SetConsoleFont");
|
||||
GetCurrentConsoleFontType *pGetCurrentConsoleFont =
|
||||
(GetCurrentConsoleFontType*)GetProcAddress(dll, "GetCurrentConsoleFont");
|
||||
SetCurrentConsoleFontExType *pSetCurrentConsoleFontEx =
|
||||
(SetCurrentConsoleFontExType*)GetProcAddress(dll, "SetCurrentConsoleFontEx");
|
||||
GetConsoleFontSizeType *pGetConsoleFontSize =
|
||||
(GetConsoleFontSizeType*)GetProcAddress(dll, "GetConsoleFontSize");
|
||||
|
||||
BOOL success;
|
||||
|
||||
// The undocumented GetNumberOfConsoleFonts API reports that my Windows 7
|
||||
// system has 12 fonts on it. Each font is really just a differently-sized
|
||||
// raster/Terminal font. Font index 0 is the smallest font, so we want to
|
||||
// choose it.
|
||||
if (pGetConsoleFontSize == NULL) {
|
||||
// This API should exist even on Windows XP.
|
||||
trace("error: GetConsoleFontSize API is missing");
|
||||
return;
|
||||
}
|
||||
if (pGetCurrentConsoleFont == NULL) {
|
||||
// This API should exist even on Windows XP.
|
||||
trace("error: GetCurrentConsoleFont API is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
AGENT_CONSOLE_FONT_INFO fi;
|
||||
success = pGetCurrentConsoleFont(m_conout, FALSE, &fi);
|
||||
if (!success) {
|
||||
trace("error: GetCurrentConsoleFont failed");
|
||||
return;
|
||||
}
|
||||
COORD smallest = pGetConsoleFontSize(m_conout, 0);
|
||||
if (smallest.X == 0 || smallest.Y == 0) {
|
||||
trace("error: GetConsoleFontSize failed");
|
||||
return;
|
||||
}
|
||||
trace("font #0: X=%d Y=%d", smallest.X, smallest.Y);
|
||||
trace("current font: idx=%d X=%d Y=%d",
|
||||
(int)fi.nFont, fi.dwFontSize.X, fi.dwFontSize.Y);
|
||||
if (fi.dwFontSize.X <= smallest.X && fi.dwFontSize.Y <= smallest.Y)
|
||||
return;
|
||||
|
||||
// First try to call the documented Vista API.
|
||||
if (pSetCurrentConsoleFontEx != NULL) {
|
||||
AGENT_CONSOLE_FONT_INFOEX fix = {0};
|
||||
fix.cbSize = sizeof(fix);
|
||||
fix.nFont = 0;
|
||||
fix.dwFontSize = smallest;
|
||||
success = pSetCurrentConsoleFontEx(m_conout, FALSE, &fix);
|
||||
trace("SetCurrentConsoleFontEx call %s",
|
||||
success ? "succeeded" : "failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Then try to call the undocumented Windows XP API.
|
||||
//
|
||||
// Somewhat described here:
|
||||
// http://blogs.microsoft.co.il/blogs/pavely/archive/2009/07/23/changing-console-fonts.aspx
|
||||
//
|
||||
if (pSetConsoleFont != NULL) {
|
||||
success = pSetConsoleFont(m_conout, 0);
|
||||
trace("SetConsoleFont call %s", success ? "succeeded" : "failed");
|
||||
return;
|
||||
}
|
||||
|
||||
trace("Not setting console font size -- "
|
||||
"neither SetConsoleFont nor SetCurrentConsoleFontEx API exists");
|
||||
}
|
||||
|
||||
Coord Win32Console::bufferSize()
|
||||
{
|
||||
// TODO: error handling
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (!GetConsoleScreenBufferInfo(m_conout, &info)) {
|
||||
trace("GetConsoleScreenBufferInfo failed");
|
||||
}
|
||||
return info.dwSize;
|
||||
}
|
||||
|
||||
SmallRect Win32Console::windowRect()
|
||||
{
|
||||
// TODO: error handling
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (!GetConsoleScreenBufferInfo(m_conout, &info)) {
|
||||
trace("GetConsoleScreenBufferInfo failed");
|
||||
}
|
||||
return info.srWindow;
|
||||
}
|
||||
|
||||
void Win32Console::resizeBuffer(const Coord &size)
|
||||
{
|
||||
// TODO: error handling
|
||||
if (!SetConsoleScreenBufferSize(m_conout, size)) {
|
||||
trace("SetConsoleScreenBufferSize failed");
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Console::moveWindow(const SmallRect &rect)
|
||||
{
|
||||
// TODO: error handling
|
||||
if (!SetConsoleWindowInfo(m_conout, TRUE, &rect)) {
|
||||
trace("SetConsoleWindowInfo failed");
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Console::reposition(const Coord &newBufferSize,
|
||||
const SmallRect &newWindowRect)
|
||||
{
|
||||
// Windows has one API for resizing the screen buffer and a different one
|
||||
// for resizing the window. It seems that either API can fail if the
|
||||
// window does not fit on the screen buffer.
|
||||
|
||||
const SmallRect origWindowRect(windowRect());
|
||||
const SmallRect origBufferRect(Coord(), bufferSize());
|
||||
|
||||
ASSERT(!newBufferSize.isEmpty());
|
||||
SmallRect bufferRect(Coord(), newBufferSize);
|
||||
ASSERT(bufferRect.contains(newWindowRect));
|
||||
|
||||
SmallRect tempWindowRect = origWindowRect.intersected(bufferRect);
|
||||
if (tempWindowRect.width() <= 0) {
|
||||
tempWindowRect.setLeft(newBufferSize.X - 1);
|
||||
tempWindowRect.setWidth(1);
|
||||
}
|
||||
if (tempWindowRect.height() <= 0) {
|
||||
tempWindowRect.setTop(newBufferSize.Y - 1);
|
||||
tempWindowRect.setHeight(1);
|
||||
}
|
||||
|
||||
// Alternatively, if we can immediately use the new window size,
|
||||
// do that instead.
|
||||
if (origBufferRect.contains(newWindowRect))
|
||||
tempWindowRect = newWindowRect;
|
||||
|
||||
if (tempWindowRect != origWindowRect)
|
||||
moveWindow(tempWindowRect);
|
||||
resizeBuffer(newBufferSize);
|
||||
if (newWindowRect != tempWindowRect)
|
||||
moveWindow(newWindowRect);
|
||||
}
|
||||
|
||||
Coord Win32Console::cursorPosition()
|
||||
{
|
||||
// TODO: error handling
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (!GetConsoleScreenBufferInfo(m_conout, &info)) {
|
||||
trace("GetConsoleScreenBufferInfo failed");
|
||||
}
|
||||
return info.dwCursorPosition;
|
||||
}
|
||||
|
||||
void Win32Console::setCursorPosition(const Coord &coord)
|
||||
{
|
||||
// TODO: error handling
|
||||
if (!SetConsoleCursorPosition(m_conout, coord)) {
|
||||
trace("SetConsoleCursorPosition failed");
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Console::writeInput(const INPUT_RECORD *ir, int count)
|
||||
{
|
||||
// TODO: error handling
|
||||
DWORD dummy = 0;
|
||||
if (!WriteConsoleInput(m_conin, ir, count, &dummy)) {
|
||||
trace("WriteConsoleInput failed");
|
||||
}
|
||||
}
|
||||
|
||||
bool Win32Console::processedInputMode()
|
||||
{
|
||||
// TODO: error handling
|
||||
DWORD mode = 0;
|
||||
if (!GetConsoleMode(m_conin, &mode)) {
|
||||
trace("GetConsoleMode failed");
|
||||
}
|
||||
return (mode & ENABLE_PROCESSED_INPUT) == ENABLE_PROCESSED_INPUT;
|
||||
}
|
||||
|
||||
void Win32Console::read(const SmallRect &rect, CHAR_INFO *data)
|
||||
{
|
||||
// TODO: error handling
|
||||
SmallRect tmp(rect);
|
||||
if (!ReadConsoleOutput(m_conout, data, rect.size(), Coord(), &tmp)) {
|
||||
trace("ReadConsoleOutput failed [x:%d,y:%d,w:%d,h:%d]",
|
||||
rect.Left, rect.Top, rect.width(), rect.height());
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Console::write(const SmallRect &rect, const CHAR_INFO *data)
|
||||
{
|
||||
// TODO: error handling
|
||||
SmallRect tmp(rect);
|
||||
if (!WriteConsoleOutput(m_conout, data, rect.size(), Coord(), &tmp)) {
|
||||
trace("WriteConsoleOutput failed");
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011-2015 Ryan Prichard
|
||||
// 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
|
||||
@ -18,36 +18,47 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef UNIX_ADAPTER_OUTPUT_HANDLER_H
|
||||
#define UNIX_ADAPTER_OUTPUT_HANDLER_H
|
||||
#ifndef WIN32CONSOLE_H
|
||||
#define WIN32CONSOLE_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include "Coord.h"
|
||||
#include "SmallRect.h"
|
||||
|
||||
#include "WakeupFd.h"
|
||||
|
||||
// Connect winpty CONOUT/CONERR to a Cygwin blocking fd.
|
||||
class OutputHandler {
|
||||
class Win32Console
|
||||
{
|
||||
public:
|
||||
OutputHandler(HANDLE conout, int outputfd, WakeupFd &completionWakeup);
|
||||
~OutputHandler() { shutdown(); }
|
||||
bool isComplete() { return m_threadCompleted; }
|
||||
void shutdown();
|
||||
Win32Console();
|
||||
~Win32Console();
|
||||
|
||||
HANDLE conin();
|
||||
HANDLE conout();
|
||||
HWND hwnd();
|
||||
void postCloseMessage();
|
||||
void setSmallFont();
|
||||
|
||||
// Buffer and window sizes.
|
||||
Coord bufferSize();
|
||||
SmallRect windowRect();
|
||||
void resizeBuffer(const Coord &size);
|
||||
void moveWindow(const SmallRect &rect);
|
||||
void reposition(const Coord &bufferSize, const SmallRect &windowRect);
|
||||
|
||||
// Cursor.
|
||||
Coord cursorPosition();
|
||||
void setCursorPosition(const Coord &point);
|
||||
|
||||
// Input stream.
|
||||
void writeInput(const INPUT_RECORD *ir, int count=1);
|
||||
bool processedInputMode();
|
||||
|
||||
// Screen content.
|
||||
void read(const SmallRect &rect, CHAR_INFO *data);
|
||||
void write(const SmallRect &rect, const CHAR_INFO *data);
|
||||
|
||||
private:
|
||||
static void *threadProcS(void *pvthis) {
|
||||
reinterpret_cast<OutputHandler*>(pvthis)->threadProc();
|
||||
return NULL;
|
||||
}
|
||||
void threadProc();
|
||||
|
||||
HANDLE m_conin;
|
||||
HANDLE m_conout;
|
||||
int m_outputfd;
|
||||
pthread_t m_thread;
|
||||
WakeupFd &m_completionWakeup;
|
||||
bool m_threadHasBeenJoined;
|
||||
volatile sig_atomic_t m_threadCompleted;
|
||||
};
|
||||
|
||||
#endif // UNIX_ADAPTER_OUTPUT_HANDLER_H
|
||||
#endif // WIN32CONSOLE_H
|
@ -18,21 +18,34 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef DEBUGCLIENT_H
|
||||
#define DEBUGCLIENT_H
|
||||
#include "Agent.h"
|
||||
#include "AgentAssert.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "winpty_snprintf.h"
|
||||
static wchar_t *heapMbsToWcs(const char *text)
|
||||
{
|
||||
size_t len = mbstowcs(NULL, text, 0);
|
||||
ASSERT(len != (size_t)-1);
|
||||
wchar_t *ret = new wchar_t[len + 1];
|
||||
size_t len2 = mbstowcs(ret, text, len + 1);
|
||||
ASSERT(len == len2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool isTracingEnabled();
|
||||
bool hasDebugFlag(const char *flag);
|
||||
void trace(const char *format, ...) WINPTY_SNPRINTF_FORMAT(1, 2);
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 5) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s controlPipeName dataPipeName cols rows\n"
|
||||
"(Note: This program is intended to be run by libwinpty.dll.)\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// This macro calls trace without evaluating the arguments.
|
||||
#define TRACE(format, ...) \
|
||||
do { \
|
||||
if (isTracingEnabled()) { \
|
||||
trace((format), ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#endif // DEBUGCLIENT_H
|
||||
Agent agent(heapMbsToWcs(argv[1]),
|
||||
heapMbsToWcs(argv[2]),
|
||||
atoi(argv[3]),
|
||||
atoi(argv[4]));
|
||||
agent.run();
|
||||
}
|
16
appveyor.yml
16
appveyor.yml
@ -1,16 +0,0 @@
|
||||
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
|
0
build/.gitkeep
Normal file
0
build/.gitkeep
Normal file
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2011-2015 Ryan Prichard
|
||||
# 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
|
||||
@ -18,24 +18,26 @@
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
ALL_TARGETS += build/$(UNIX_ADAPTER_EXE)
|
||||
CFLAGS += -MMD -Wall
|
||||
CXXFLAGS += -MMD -Wall
|
||||
|
||||
$(eval $(call def_unix_target,unix-adapter,))
|
||||
# Use gmake -n to see the command-lines gmake would run.
|
||||
|
||||
UNIX_ADAPTER_OBJECTS = \
|
||||
build/unix-adapter/unix-adapter/InputHandler.o \
|
||||
build/unix-adapter/unix-adapter/OutputHandler.o \
|
||||
build/unix-adapter/unix-adapter/Util.o \
|
||||
build/unix-adapter/unix-adapter/WakeupFd.o \
|
||||
build/unix-adapter/unix-adapter/main.o \
|
||||
build/unix-adapter/shared/DebugClient.o \
|
||||
build/unix-adapter/shared/WinptyAssert.o \
|
||||
build/unix-adapter/shared/WinptyVersion.o
|
||||
%.o : %.c
|
||||
@echo Compiling $<
|
||||
@$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
build/unix-adapter/shared/WinptyVersion.o : build/gen/GenVersion.h
|
||||
%.o : %.cc
|
||||
@echo Compiling $<
|
||||
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
build/$(UNIX_ADAPTER_EXE) : $(UNIX_ADAPTER_OBJECTS) build/winpty.dll
|
||||
$(info Linking $@)
|
||||
@$(UNIX_CXX) $(UNIX_LDFLAGS) -o $@ $^
|
||||
%.o : ../shared/%.cc
|
||||
@echo Compiling $<
|
||||
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
-include $(UNIX_ADAPTER_OBJECTS:.o=.d)
|
||||
# Attempt to detect whether configure has been run yet. The CWD will
|
||||
# be one of the subdirectories, so refer to ../config-mingw.mk instead
|
||||
# of ./config-mingw.mk.
|
||||
ifeq "$(wildcard ../config-mingw.mk)" ""
|
||||
$(error config-mingw.mk does not exist. Please run ./configure)
|
||||
endif
|
126
configure
vendored
126
configure
vendored
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2011-2015 Ryan Prichard
|
||||
# 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
|
||||
@ -45,88 +45,25 @@ function findTool {
|
||||
}
|
||||
|
||||
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++'
|
||||
IS_MSYS=0
|
||||
|
||||
# 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++
|
||||
UNIX_GPP=i686-pc-cygwin-g++
|
||||
MINGW_GPP="i686-pc-mingw32-g++ i686-w64-mingw32-g++"
|
||||
UNIX_LDFLAGS_STATIC_LIBSTDCXX="-static-libgcc -static-libstdc++"
|
||||
;;
|
||||
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
|
||||
MINGW*)
|
||||
echo 'uname -s identifies a MSYS environment.'
|
||||
IS_MSYS=1
|
||||
UNIX_GPP=i686-pc-msys-g++
|
||||
MINGW_GPP=mingw32-g++
|
||||
# The MSYS compiler does not recognize -static-libstdc++. There is a
|
||||
# msys-1.0.dll, but no gcc or stdc++ DLL.
|
||||
UNIX_LDFLAGS_STATIC_LIBSTDCXX=
|
||||
;;
|
||||
*)
|
||||
echo 'Error: uname -s did not match either CYGWIN* or MINGW*.'
|
||||
@ -135,33 +72,14 @@ case $(uname -s) in
|
||||
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
|
||||
findTool "Cygwin/MSYS G++ compiler" "$UNIX_GPP"
|
||||
UNIX_GPP=$FINDTOOL_OUT
|
||||
findTool "32-bit MinGW G++ compiler" "$MINGW_GPP"
|
||||
MINGW_GPP=$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
|
||||
echo Writing config-unix.mk
|
||||
echo CXX=$UNIX_GPP > config-unix.mk
|
||||
echo LDFLAGS_STATIC_LIBSTDCXX=$UNIX_LDFLAGS_STATIC_LIBSTDCXX >> config-unix.mk
|
||||
echo Writing config-mingw.mk
|
||||
echo CXX=$MINGW_GPP > config-mingw.mk
|
||||
|
108
include/winpty.h
Normal file
108
include/winpty.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WINPTY_H
|
||||
#define WINPTY_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef WINPTY
|
||||
#define WINPTY_API __declspec(dllexport)
|
||||
#else
|
||||
#define WINPTY_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct winpty_s winpty_t;
|
||||
|
||||
/*
|
||||
* winpty API.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Starts a new winpty instance with the given size.
|
||||
*
|
||||
* This function creates a new agent process and connects to it.
|
||||
*/
|
||||
WINPTY_API winpty_t *winpty_open(int cols, int rows);
|
||||
|
||||
/**
|
||||
* Starts a new winpty instance with the given size.
|
||||
*
|
||||
* This function creates a new agent process and connects to it.
|
||||
* By using this method you are responsible for creating your own named
|
||||
* pipe server for communicating with the child process.
|
||||
*
|
||||
*/
|
||||
WINPTY_API winpty_t *winpty_open_use_own_datapipe(const wchar_t *dataPipe, int cols, int rows);
|
||||
|
||||
/*
|
||||
* Start a child process. Either (but not both) of appname and cmdline may
|
||||
* be NULL. cwd and env may be NULL. env is a pointer to an environment
|
||||
* block like that passed to CreateProcess.
|
||||
*
|
||||
* This function never modifies the cmdline, unlike CreateProcess.
|
||||
*
|
||||
* Only one child process may be started. After the child process exits, the
|
||||
* agent will scrape the console output one last time, then close the data pipe
|
||||
* once all remaining data has been sent.
|
||||
*
|
||||
* Returns 0 on success or a Win32 error code on failure.
|
||||
*/
|
||||
WINPTY_API int winpty_start_process(winpty_t *pc,
|
||||
const wchar_t *appname,
|
||||
const wchar_t *cmdline,
|
||||
const wchar_t *cwd,
|
||||
const wchar_t *env);
|
||||
|
||||
/*
|
||||
* Returns the exit code of the process started with winpty_start_process,
|
||||
* or -1 none is available.
|
||||
*/
|
||||
WINPTY_API int winpty_get_exit_code(winpty_t *pc);
|
||||
|
||||
/*
|
||||
* Returns an overlapped-mode pipe handle that can be read and written
|
||||
* like a Unix terminal.
|
||||
*/
|
||||
WINPTY_API HANDLE winpty_get_data_pipe(winpty_t *pc);
|
||||
|
||||
/*
|
||||
* Change the size of the Windows console.
|
||||
*/
|
||||
WINPTY_API int winpty_set_size(winpty_t *pc, int cols, int rows);
|
||||
|
||||
/*
|
||||
* Closes the winpty.
|
||||
*/
|
||||
WINPTY_API void winpty_exit(winpty_t *pc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WINPTY_H */
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2011-2015 Ryan Prichard
|
||||
# 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
|
||||
@ -18,29 +18,28 @@
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
ALL_TARGETS += build/winpty.dll
|
||||
include ../config.mk
|
||||
include ../config-mingw.mk
|
||||
|
||||
$(eval $(call def_mingw_target,libwinpty,-DCOMPILING_WINPTY_DLL))
|
||||
LIBRARY = ../build/winpty.dll
|
||||
OBJECTS = winpty.o DebugClient.o
|
||||
LDFLAGS += -shared -static-libgcc -static-libstdc++
|
||||
|
||||
LIBWINPTY_OBJECTS = \
|
||||
build/libwinpty/libwinpty/AgentLocation.o \
|
||||
build/libwinpty/libwinpty/winpty.o \
|
||||
build/libwinpty/shared/BackgroundDesktop.o \
|
||||
build/libwinpty/shared/Buffer.o \
|
||||
build/libwinpty/shared/DebugClient.o \
|
||||
build/libwinpty/shared/GenRandom.o \
|
||||
build/libwinpty/shared/OwnedHandle.o \
|
||||
build/libwinpty/shared/StringUtil.o \
|
||||
build/libwinpty/shared/WindowsSecurity.o \
|
||||
build/libwinpty/shared/WindowsVersion.o \
|
||||
build/libwinpty/shared/WinptyAssert.o \
|
||||
build/libwinpty/shared/WinptyException.o \
|
||||
build/libwinpty/shared/WinptyVersion.o
|
||||
CXXFLAGS += \
|
||||
-I../include \
|
||||
-DUNICODE \
|
||||
-D_UNICODE \
|
||||
-D_WIN32_WINNT=0x0501 \
|
||||
-DWINPTY \
|
||||
-fno-exceptions \
|
||||
-fno-rtti
|
||||
|
||||
build/libwinpty/shared/WinptyVersion.o : build/gen/GenVersion.h
|
||||
$(LIBRARY) : $(OBJECTS)
|
||||
@echo Linking $@
|
||||
@$(CXX) $(LDFLAGS) -o $@ $^
|
||||
|
||||
build/winpty.dll : $(LIBWINPTY_OBJECTS)
|
||||
$(info Linking $@)
|
||||
@$(MINGW_CXX) $(MINGW_LDFLAGS) -shared -o $@ $^ -Wl,--out-implib,build/winpty.lib
|
||||
.PHONY : clean
|
||||
clean :
|
||||
rm -f $(LIBRARY) *.o *.d
|
||||
|
||||
-include $(LIBWINPTY_OBJECTS:.o=.d)
|
||||
-include $(OBJECTS:.o=.d)
|
507
libwinpty/winpty.cc
Normal file
507
libwinpty/winpty.cc
Normal file
@ -0,0 +1,507 @@
|
||||
// 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.
|
||||
|
||||
#include <winpty.h>
|
||||
#include <windows.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
std::string to_utf8(const wchar_t* buffer, int len)
|
||||
{
|
||||
int nChars = ::WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
0,
|
||||
buffer,
|
||||
len,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
if (nChars == 0) return "";
|
||||
|
||||
std::string newbuffer;
|
||||
newbuffer.resize(nChars) ;
|
||||
::WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
0,
|
||||
buffer,
|
||||
len,
|
||||
const_cast< char* >(newbuffer.c_str()),
|
||||
nChars,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
return newbuffer;
|
||||
}
|
||||
|
||||
std::string to_utf8(const std::wstring& str)
|
||||
{
|
||||
return to_utf8(str.c_str(), (int)str.size());
|
||||
}
|
||||
|
||||
std::wstring to_wstring(const std::string& s)
|
||||
{
|
||||
int len;
|
||||
int slength = (int)s.length() + 1;
|
||||
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
|
||||
wchar_t* buf = new wchar_t[len];
|
||||
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
|
||||
std::wstring r(buf);
|
||||
delete[] buf;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "../shared/DebugClient.h"
|
||||
#include "../shared/AgentMsg.h"
|
||||
#include "../shared/Buffer.h"
|
||||
#include "../shared/c99_snprintf.h"
|
||||
|
||||
// TODO: Error handling, handle out-of-memory.
|
||||
|
||||
#define AGENT_EXE L"winpty-agent.exe"
|
||||
|
||||
static volatile LONG consoleCounter;
|
||||
|
||||
struct winpty_s {
|
||||
winpty_s();
|
||||
HANDLE controlPipe;
|
||||
HANDLE dataPipe;
|
||||
};
|
||||
|
||||
winpty_s::winpty_s() : controlPipe(NULL), dataPipe(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
static HMODULE getCurrentModule()
|
||||
{
|
||||
HMODULE module;
|
||||
if (!GetModuleHandleEx(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
(LPCTSTR)getCurrentModule,
|
||||
&module)) {
|
||||
assert(false);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
static std::wstring getModuleFileName(HMODULE module)
|
||||
{
|
||||
const int bufsize = 4096;
|
||||
wchar_t path[bufsize];
|
||||
int size = GetModuleFileName(module, path, bufsize);
|
||||
assert(size != 0 && size != bufsize);
|
||||
return std::wstring(path);
|
||||
}
|
||||
|
||||
static std::wstring dirname(const std::wstring &path)
|
||||
{
|
||||
std::wstring::size_type pos = path.find_last_of(L"\\/");
|
||||
if (pos == std::wstring::npos)
|
||||
return L"";
|
||||
else
|
||||
return path.substr(0, pos);
|
||||
}
|
||||
|
||||
static bool pathExists(const std::wstring &path)
|
||||
{
|
||||
return GetFileAttributes(path.c_str()) != 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static std::wstring findAgentProgram()
|
||||
{
|
||||
std::wstring progDir = dirname(getModuleFileName(getCurrentModule()));
|
||||
std::wstring ret = progDir + (L"\\" AGENT_EXE);
|
||||
assert(pathExists(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Call ConnectNamedPipe and block, even for an overlapped pipe. If the
|
||||
// pipe is overlapped, create a temporary event for use connecting.
|
||||
static bool connectNamedPipe(HANDLE handle, bool overlapped)
|
||||
{
|
||||
OVERLAPPED over, *pover = NULL;
|
||||
if (overlapped) {
|
||||
pover = &over;
|
||||
memset(&over, 0, sizeof(over));
|
||||
over.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
assert(over.hEvent != NULL);
|
||||
}
|
||||
bool success = ConnectNamedPipe(handle, pover);
|
||||
if (overlapped && !success && GetLastError() == ERROR_IO_PENDING) {
|
||||
DWORD actual;
|
||||
success = GetOverlappedResult(handle, pover, &actual, TRUE);
|
||||
}
|
||||
if (!success && GetLastError() == ERROR_PIPE_CONNECTED)
|
||||
success = TRUE;
|
||||
if (overlapped)
|
||||
CloseHandle(over.hEvent);
|
||||
return success;
|
||||
}
|
||||
|
||||
static void writePacket(winpty_t *pc, const WriteBuffer &packet)
|
||||
{
|
||||
std::string payload = packet.str();
|
||||
|
||||
int32_t payloadSize = payload.size();
|
||||
DWORD actual;
|
||||
BOOL success = WriteFile(pc->controlPipe, &payloadSize, sizeof(int32_t), &actual, NULL);
|
||||
|
||||
assert(success && actual == sizeof(int32_t));
|
||||
|
||||
success = WriteFile(pc->controlPipe, payload.c_str(), payloadSize, &actual, NULL);
|
||||
assert(success && (int32_t)actual == payloadSize);
|
||||
}
|
||||
|
||||
static int32_t readInt32(winpty_t *pc)
|
||||
{
|
||||
int32_t result;
|
||||
DWORD actual;
|
||||
BOOL success = ReadFile(pc->controlPipe, &result, sizeof(int32_t), &actual, NULL);
|
||||
assert(success && actual == sizeof(int32_t));
|
||||
return result;
|
||||
}
|
||||
|
||||
static HANDLE createNamedPipe(const std::wstring &name, bool overlapped)
|
||||
{
|
||||
return CreateNamedPipe(name.c_str(),
|
||||
/*dwOpenMode=*/
|
||||
PIPE_ACCESS_DUPLEX |
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE |
|
||||
(overlapped ? FILE_FLAG_OVERLAPPED : 0),
|
||||
/*dwPipeMode=*/0,
|
||||
/*nMaxInstances=*/1,
|
||||
/*nOutBufferSize=*/0,
|
||||
/*nInBufferSize=*/0,
|
||||
/*nDefaultTimeOut=*/3000,
|
||||
NULL);
|
||||
}
|
||||
|
||||
struct BackgroundDesktop {
|
||||
HWINSTA originalStation;
|
||||
HWINSTA station;
|
||||
HDESK desktop;
|
||||
std::wstring desktopName;
|
||||
};
|
||||
|
||||
static std::wstring getObjectName(HANDLE object)
|
||||
{
|
||||
BOOL success;
|
||||
DWORD lengthNeeded = 0;
|
||||
GetUserObjectInformation(object, UOI_NAME,
|
||||
NULL, 0,
|
||||
&lengthNeeded);
|
||||
assert(lengthNeeded % sizeof(wchar_t) == 0);
|
||||
wchar_t *tmp = new wchar_t[lengthNeeded / 2];
|
||||
success = GetUserObjectInformation(object, UOI_NAME,
|
||||
tmp, lengthNeeded,
|
||||
NULL);
|
||||
assert(success);
|
||||
std::wstring ret = tmp;
|
||||
delete [] tmp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get a non-interactive window station for the agent.
|
||||
// TODO: review security w.r.t. windowstation and desktop.
|
||||
static BackgroundDesktop setupBackgroundDesktop()
|
||||
{
|
||||
BackgroundDesktop ret;
|
||||
ret.originalStation = GetProcessWindowStation();
|
||||
ret.station = CreateWindowStation(NULL, 0, WINSTA_ALL_ACCESS, NULL);
|
||||
bool success = SetProcessWindowStation(ret.station);
|
||||
assert(success);
|
||||
ret.desktop = CreateDesktop(L"Default", NULL, NULL, 0, GENERIC_ALL, NULL);
|
||||
assert(ret.originalStation != NULL);
|
||||
assert(ret.station != NULL);
|
||||
assert(ret.desktop != NULL);
|
||||
ret.desktopName =
|
||||
getObjectName(ret.station) + L"\\" + getObjectName(ret.desktop);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void restoreOriginalDesktop(const BackgroundDesktop &desktop)
|
||||
{
|
||||
SetProcessWindowStation(desktop.originalStation);
|
||||
CloseDesktop(desktop.desktop);
|
||||
CloseWindowStation(desktop.station);
|
||||
}
|
||||
|
||||
static std::wstring getDesktopFullName()
|
||||
{
|
||||
// MSDN says that the handle returned by GetThreadDesktop does not need
|
||||
// to be passed to CloseDesktop.
|
||||
HWINSTA station = GetProcessWindowStation();
|
||||
HDESK desktop = GetThreadDesktop(GetCurrentThreadId());
|
||||
assert(station != NULL);
|
||||
assert(desktop != NULL);
|
||||
return getObjectName(station) + L"\\" + getObjectName(desktop);
|
||||
}
|
||||
|
||||
static void startAgentProcess(const BackgroundDesktop &desktop,
|
||||
std::wstring &controlPipeName,
|
||||
std::wstring &dataPipeName,
|
||||
int cols, int rows)
|
||||
{
|
||||
bool success;
|
||||
|
||||
std::wstring agentProgram = findAgentProgram();
|
||||
std::wstringstream agentCmdLineStream;
|
||||
agentCmdLineStream << L"\"" << agentProgram << L"\" "
|
||||
<< controlPipeName << " " << dataPipeName << " "
|
||||
<< cols << " " << rows;
|
||||
std::wstring agentCmdLine = agentCmdLineStream.str();
|
||||
|
||||
// Start the agent.
|
||||
STARTUPINFO sui;
|
||||
memset(&sui, 0, sizeof(sui));
|
||||
sui.cb = sizeof(sui);
|
||||
sui.lpDesktop = (LPWSTR)desktop.desktopName.c_str();
|
||||
PROCESS_INFORMATION pi;
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
std::vector<wchar_t> cmdline(agentCmdLine.size() + 1);
|
||||
agentCmdLine.copy(&cmdline[0], agentCmdLine.size());
|
||||
cmdline[agentCmdLine.size()] = L'\0';
|
||||
success = CreateProcess(agentProgram.c_str(),
|
||||
&cmdline[0],
|
||||
NULL, NULL,
|
||||
/*bInheritHandles=*/FALSE,
|
||||
/*dwCreationFlags=*/CREATE_NEW_CONSOLE,
|
||||
NULL, NULL,
|
||||
&sui, &pi);
|
||||
if (!success) {
|
||||
fprintf(stderr,
|
||||
"Error %#x starting %ls\n",
|
||||
(unsigned int)GetLastError(),
|
||||
agentCmdLine.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
WINPTY_API winpty_t *winpty_open(int cols, int rows)
|
||||
{
|
||||
winpty_t *pc = new winpty_t;
|
||||
|
||||
// Start pipes.
|
||||
std::wstringstream pipeName;
|
||||
|
||||
// Allow custom pipe names.
|
||||
pipeName << L"\\\\.\\pipe\\winpty-" << GetCurrentProcessId()
|
||||
<< L"-" << InterlockedIncrement(&consoleCounter);
|
||||
std::wstring controlPipeName = pipeName.str() + L"-control";
|
||||
std::wstring dataPipeName = pipeName.str() + L"-data";
|
||||
|
||||
pc->controlPipe = createNamedPipe(controlPipeName, false);
|
||||
if (pc->controlPipe == INVALID_HANDLE_VALUE) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
pc->dataPipe = createNamedPipe(dataPipeName, true);
|
||||
if (pc->dataPipe == INVALID_HANDLE_VALUE) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Setup a background desktop for the agent.
|
||||
BackgroundDesktop desktop = setupBackgroundDesktop();
|
||||
|
||||
// Start the agent.
|
||||
startAgentProcess(desktop, controlPipeName, dataPipeName, cols, rows);
|
||||
|
||||
// TODO: Frequently, I see the CreateProcess call return successfully,
|
||||
// but the agent immediately dies. The following pipe connect calls then
|
||||
// hang. These calls should probably timeout. Maybe this code could also
|
||||
// poll the agent process handle?
|
||||
|
||||
// Connect the pipes.
|
||||
bool success;
|
||||
success = connectNamedPipe(pc->controlPipe, false);
|
||||
if (!success) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
success = connectNamedPipe(pc->dataPipe, true);
|
||||
if (!success) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Close handles to the background desktop and restore the original window
|
||||
// station. This must wait until we know the agent is running -- if we
|
||||
// close these handles too soon, then the desktop and windowstation will be
|
||||
// destroyed before the agent can connect with them.
|
||||
restoreOriginalDesktop(desktop);
|
||||
|
||||
// The default security descriptor for a named pipe allows anyone to connect
|
||||
// to the pipe to read, but not to write. Only the "creator owner" and
|
||||
// various system accounts can write to the pipe. By sending and receiving
|
||||
// a dummy message on the control pipe, we should confirm that something
|
||||
// trusted (i.e. the agent we just started) successfully connected and wrote
|
||||
// to one of our pipes.
|
||||
WriteBuffer packet;
|
||||
packet.putInt(AgentMsg::Ping);
|
||||
writePacket(pc, packet);
|
||||
if (readInt32(pc) != 0) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// TODO: On Windows Vista and forward, we could call
|
||||
// GetNamedPipeClientProcessId and verify that the PID is correct. We could
|
||||
// also pass the PIPE_REJECT_REMOTE_CLIENTS flag on newer OS's.
|
||||
// TODO: I suppose this code is still subject to a denial-of-service attack
|
||||
// from untrusted accounts making read-only connections to the pipe. It
|
||||
// should probably provide a SECURITY_DESCRIPTOR for the pipe, but the last
|
||||
// time I tried that (using SDDL), I couldn't get it to work (access denied
|
||||
// errors).
|
||||
|
||||
// Aside: An obvious way to setup these handles is to open both ends of the
|
||||
// pipe in the parent process and let the child inherit its handles.
|
||||
// Unfortunately, the Windows API makes inheriting handles problematic.
|
||||
// MSDN says that handles have to be marked inheritable, and once they are,
|
||||
// they are inherited by any call to CreateProcess with
|
||||
// bInheritHandles==TRUE. To avoid accidental inheritance, the library's
|
||||
// clients would be obligated not to create new processes while a thread
|
||||
// was calling winpty_open. Moreover, to inherit handles, MSDN seems
|
||||
// to say that bInheritHandles must be TRUE[*], but I don't want to use a
|
||||
// TRUE bInheritHandles, because I want to avoid leaking handles into the
|
||||
// agent process, especially if the library someday allows creating the
|
||||
// agent process under a different user account.
|
||||
//
|
||||
// [*] The way that bInheritHandles and STARTF_USESTDHANDLES work together
|
||||
// is unclear in the documentation. On one hand, for STARTF_USESTDHANDLES,
|
||||
// it says that bInheritHandles must be TRUE. On Vista and up, isn't
|
||||
// PROC_THREAD_ATTRIBUTE_HANDLE_LIST an acceptable alternative to
|
||||
// bInheritHandles? On the other hand, KB315939 contradicts the
|
||||
// STARTF_USESTDHANDLES documentation by saying, "Your pipe handles will
|
||||
// still be duplicated because Windows will always duplicate the STD
|
||||
// handles, even when bInheritHandles is set to FALSE." IIRC, my testing
|
||||
// showed that the KB article was correct.
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
WINPTY_API winpty_t *winpty_open_use_own_datapipe(const wchar_t *dataPipe, int cols, int rows)
|
||||
{
|
||||
|
||||
winpty_t *pc = new winpty_t;
|
||||
|
||||
// Setup pipes.
|
||||
std::wstringstream pipeName;
|
||||
pipeName << L"\\\\.\\pipe\\winpty-" << GetCurrentProcessId()
|
||||
<< L"-" << InterlockedIncrement(&consoleCounter);
|
||||
std::wstring controlPipeName = pipeName.str() + L"-control";
|
||||
|
||||
// The callee provides his own pipe implementation for handling sending/recieving
|
||||
// data between the started child process.
|
||||
std::wstring dataPipeName(to_wstring(to_utf8(dataPipe)));
|
||||
|
||||
// Create control pipe
|
||||
pc->controlPipe = createNamedPipe(controlPipeName, false);
|
||||
if (pc->controlPipe == INVALID_HANDLE_VALUE) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Setup a background desktop for the agent.
|
||||
BackgroundDesktop desktop = setupBackgroundDesktop();
|
||||
|
||||
// Start the agent.
|
||||
startAgentProcess(desktop, controlPipeName, dataPipeName, cols, rows);
|
||||
|
||||
// Test control pipe connection.
|
||||
if (!connectNamedPipe(pc->controlPipe, false)) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Restore desktop.
|
||||
restoreOriginalDesktop(desktop);
|
||||
|
||||
WriteBuffer packet;
|
||||
packet.putInt(AgentMsg::Ping);
|
||||
writePacket(pc, packet);
|
||||
if (readInt32(pc) != 0) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
WINPTY_API int winpty_start_process(winpty_t *pc,
|
||||
const wchar_t *appname,
|
||||
const wchar_t *cmdline,
|
||||
const wchar_t *cwd,
|
||||
const wchar_t *env)
|
||||
{
|
||||
|
||||
WriteBuffer packet;
|
||||
packet.putInt(AgentMsg::StartProcess);
|
||||
packet.putWString(appname ? appname : L"");
|
||||
packet.putWString(cmdline ? cmdline : L"");
|
||||
packet.putWString(cwd ? cwd : L"");
|
||||
packet.putWString(env ? env : L"");
|
||||
packet.putWString(getDesktopFullName());
|
||||
writePacket(pc, packet);
|
||||
return readInt32(pc);
|
||||
}
|
||||
|
||||
WINPTY_API int winpty_get_exit_code(winpty_t *pc)
|
||||
{
|
||||
WriteBuffer packet;
|
||||
packet.putInt(AgentMsg::GetExitCode);
|
||||
writePacket(pc, packet);
|
||||
return readInt32(pc);
|
||||
}
|
||||
|
||||
WINPTY_API HANDLE winpty_get_data_pipe(winpty_t *pc)
|
||||
{
|
||||
return pc->dataPipe;
|
||||
}
|
||||
|
||||
WINPTY_API int winpty_set_size(winpty_t *pc, int cols, int rows)
|
||||
{
|
||||
WriteBuffer packet;
|
||||
packet.putInt(AgentMsg::SetSize);
|
||||
packet.putInt(cols);
|
||||
packet.putInt(rows);
|
||||
writePacket(pc, packet);
|
||||
return readInt32(pc);
|
||||
}
|
||||
|
||||
WINPTY_API void winpty_exit(winpty_t *pc)
|
||||
{
|
||||
CloseHandle(pc->controlPipe);
|
||||
if(pc->dataPipe > 0) {
|
||||
CloseHandle(pc->dataPipe);
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// 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;
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
#
|
||||
# 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"
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
#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;
|
||||
}
|
0
misc/DebugClient.py
Executable file → Normal file
0
misc/DebugClient.py
Executable file → Normal file
0
misc/DebugServer.py
Executable file → Normal file
0
misc/DebugServer.py
Executable file → Normal file
@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
|
||||
for i in range(1, int(sys.argv[1]) + 1):
|
||||
print i, "X" * 78
|
@ -1,46 +0,0 @@
|
||||
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.
|
@ -1,528 +0,0 @@
|
||||
==================================
|
||||
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)
|
@ -1,633 +0,0 @@
|
||||
==================================
|
||||
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)
|
@ -1,630 +0,0 @@
|
||||
=======================================
|
||||
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)
|
@ -1,630 +0,0 @@
|
||||
==========================================================
|
||||
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)
|
@ -1,630 +0,0 @@
|
||||
=====================================
|
||||
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)
|
@ -1,630 +0,0 @@
|
||||
===========================================================
|
||||
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)
|
@ -1,16 +0,0 @@
|
||||
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.
|
@ -1,4 +0,0 @@
|
||||
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.
|
@ -1,144 +0,0 @@
|
||||
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.
|
@ -1,100 +0,0 @@
|
||||
#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);
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#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
misc/GetFont.cc
261
misc/GetFont.cc
@ -1,261 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
#
|
||||
# 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?)"
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
// 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;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
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.
|
@ -1,34 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
//
|
||||
// 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;
|
||||
}
|
@ -1,671 +0,0 @@
|
||||
//
|
||||
// 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;
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -2,8 +2,6 @@
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
|
||||
const int SC_CONSOLE_MARK = 0xFFF2;
|
||||
const int SC_CONSOLE_SELECT_ALL = 0xFFF5;
|
||||
|
||||
@ -12,9 +10,7 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,15 +26,14 @@ int main()
|
||||
pausingThread, NULL,
|
||||
0, NULL);
|
||||
|
||||
for (int i = 0; i < 30; ++i) {
|
||||
Sleep(100);
|
||||
while (true) {
|
||||
GetConsoleScreenBufferInfo(out, &info);
|
||||
if (memcmp(&info.dwCursorPosition, &initial, sizeof(COORD)) != 0) {
|
||||
trace("cursor moved to [%d,%d]",
|
||||
printf("cursor moved to [%d,%d]\n",
|
||||
info.dwCursorPosition.X,
|
||||
info.dwCursorPosition.Y);
|
||||
} else {
|
||||
trace("cursor in expected position");
|
||||
GetConsoleScreenBufferInfo(out, &info);
|
||||
initial = info.dwCursorPosition;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -1,90 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
#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
misc/SetFont.cc
145
misc/SetFont.cc
@ -1,145 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#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;
|
||||
}
|
0
misc/Spew.py
Executable file → Normal file
0
misc/Spew.py
Executable file → Normal file
172
misc/TestUtil.cc
172
misc/TestUtil.cc
@ -1,172 +0,0 @@
|
||||
// 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,
|
||||
// "MS ゴシック" (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;
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
// 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"MS ゴシック",
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
@ -1,246 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
//
|
||||
// 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;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
//
|
||||
// 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;
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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); }
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc == 1) {
|
||||
startChildProcess(L"CHILD");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int WIDTH = 25;
|
||||
|
||||
setWindowPos(0, 0, 1, 1);
|
||||
setBufferSize(WIDTH, 40);
|
||||
setWindowPos(0, 0, WIDTH, 20);
|
||||
|
||||
system("cls");
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
printf("FOO(%d)\n", i);
|
||||
}
|
||||
|
||||
repeatChar(5, '\n');
|
||||
repeatChar(WIDTH * 5, '.');
|
||||
repeatChar(10, '\n');
|
||||
setWindowPos(0, 20, WIDTH, 20);
|
||||
writeBox(0, 5, 1, 10, '|');
|
||||
|
||||
Sleep(120000);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
#include "../shared/DebugClient.cc"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#include "../src/shared/DebugClient.cc"
|
||||
#include "../shared/DebugClient.cc"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -1,27 +0,0 @@
|
||||
// I noticed this on the ConEmu web site:
|
||||
//
|
||||
// https://social.msdn.microsoft.com/Forums/en-US/40c8e395-cca9-45c8-b9b8-2fbe6782ac2b/readconsoleoutput-cause-access-violation-writing-location-exception
|
||||
// https://conemu.github.io/en/MicrosoftBugs.html
|
||||
//
|
||||
// In Windows 7, 8, and 8.1, a ReadConsoleOutputW with an out-of-bounds read
|
||||
// region crashes the application. I have reproduced the problem on Windows 8
|
||||
// and 8.1, but not on Windows 7.
|
||||
//
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "TestUtil.cc"
|
||||
|
||||
int main() {
|
||||
setWindowPos(0, 0, 1, 1);
|
||||
setBufferSize(80, 25);
|
||||
setWindowPos(0, 0, 80, 25);
|
||||
|
||||
const HANDLE conout = openConout();
|
||||
static CHAR_INFO lineBuf[80];
|
||||
SMALL_RECT readRegion = { 0, 999, 79, 999 };
|
||||
const BOOL ret = ReadConsoleOutputW(conout, lineBuf, {80, 1}, {0, 0}, &readRegion);
|
||||
ASSERT(!ret && "ReadConsoleOutputW should have failed");
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static std::wstring mbsToWcs(const std::string &s) {
|
||||
const size_t len = mbstowcs(nullptr, s.c_str(), 0);
|
||||
if (len == static_cast<size_t>(-1)) {
|
||||
assert(false && "mbsToWcs: invalid string");
|
||||
}
|
||||
std::wstring ret;
|
||||
ret.resize(len);
|
||||
const size_t len2 = mbstowcs(&ret[0], s.c_str(), len);
|
||||
assert(len == len2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t parseHex(wchar_t ch, bool &invalid) {
|
||||
if (ch >= L'0' && ch <= L'9') {
|
||||
return ch - L'0';
|
||||
} else if (ch >= L'a' && ch <= L'f') {
|
||||
return ch - L'a' + 10;
|
||||
} else if (ch >= L'A' && ch <= L'F') {
|
||||
return ch - L'A' + 10;
|
||||
} else {
|
||||
invalid = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::vector<std::wstring> args;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
args.push_back(mbsToWcs(argv[i]));
|
||||
}
|
||||
|
||||
std::wstring out;
|
||||
for (const auto &arg : args) {
|
||||
if (!out.empty()) {
|
||||
out.push_back(L' ');
|
||||
}
|
||||
for (size_t i = 0; i < arg.size(); ++i) {
|
||||
wchar_t ch = arg[i];
|
||||
wchar_t nch = i + 1 < arg.size() ? arg[i + 1] : L'\0';
|
||||
if (ch == L'\\') {
|
||||
switch (nch) {
|
||||
case L'a': ch = L'\a'; ++i; break;
|
||||
case L'b': ch = L'\b'; ++i; break;
|
||||
case L'e': ch = L'\x1b'; ++i; break;
|
||||
case L'f': ch = L'\f'; ++i; break;
|
||||
case L'n': ch = L'\n'; ++i; break;
|
||||
case L'r': ch = L'\r'; ++i; break;
|
||||
case L't': ch = L'\t'; ++i; break;
|
||||
case L'v': ch = L'\v'; ++i; break;
|
||||
case L'\\': ch = L'\\'; ++i; break;
|
||||
case L'\'': ch = L'\''; ++i; break;
|
||||
case L'\"': ch = L'\"'; ++i; break;
|
||||
case L'\?': ch = L'\?'; ++i; break;
|
||||
case L'x':
|
||||
if (i + 3 < arg.size()) {
|
||||
bool invalid = false;
|
||||
uint32_t d1 = parseHex(arg[i + 2], invalid);
|
||||
uint32_t d2 = parseHex(arg[i + 3], invalid);
|
||||
if (!invalid) {
|
||||
i += 3;
|
||||
ch = (d1 << 4) | d2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case L'u':
|
||||
if (i + 5 < arg.size()) {
|
||||
bool invalid = false;
|
||||
uint32_t d1 = parseHex(arg[i + 2], invalid);
|
||||
uint32_t d2 = parseHex(arg[i + 3], invalid);
|
||||
uint32_t d3 = parseHex(arg[i + 4], invalid);
|
||||
uint32_t d4 = parseHex(arg[i + 5], invalid);
|
||||
if (!invalid) {
|
||||
i += 5;
|
||||
ch = (d1 << 24) | (d2 << 16) | (d3 << 8) | d4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
out.push_back(ch);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD actual = 0;
|
||||
if (!WriteConsoleW(
|
||||
GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
out.c_str(),
|
||||
out.size(),
|
||||
&actual,
|
||||
nullptr)) {
|
||||
fprintf(stderr, "WriteConsole failed (is stdout a console?)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
name=$1
|
||||
name=${name%.}
|
||||
name=${name%.cc}
|
||||
name=${name%.exe}
|
||||
echo Compiling $name.cc to $name.exe
|
||||
i686-w64-mingw32-g++.exe -static -std=c++11 $name.cc -o $name.exe
|
||||
i686-w64-mingw32-strip $name.exe
|
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
name=$1
|
||||
name=${name%.}
|
||||
name=${name%.cc}
|
||||
name=${name%.exe}
|
||||
echo Compiling $name.cc to $name.exe
|
||||
x86_64-w64-mingw32-g++.exe -static -std=c++11 $name.cc -o $name.exe
|
||||
x86_64-w64-mingw32-strip $name.exe
|
4
misc/build_win32.sh
Normal file
4
misc/build_win32.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
g++ Win32Echo1.cc -o Win32Echo1
|
||||
g++ Win32Echo2.cc -o Win32Echo2
|
||||
g++ Win32Write1.cc -o Win32Write1
|
@ -1,212 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
FORE=$1
|
||||
BACK=$2
|
||||
FILL=$3
|
||||
|
||||
if [ "$FORE" = "" ]; then
|
||||
FORE=DefaultFore
|
||||
fi
|
||||
if [ "$BACK" = "" ]; then
|
||||
BACK=DefaultBack
|
||||
fi
|
||||
|
||||
# To detect color changes, we want a character that fills the whole cell
|
||||
# if possible. U+2588 is perfect, except that it becomes invisible in the
|
||||
# original xterm, when bolded. For that terminal, use something else, like
|
||||
# "#" or "@".
|
||||
if [ "$FILL" = "" ]; then
|
||||
FILL="█"
|
||||
fi
|
||||
|
||||
# SGR (Select Graphic Rendition)
|
||||
s() {
|
||||
printf '\033[0m'
|
||||
while [ "$1" != "" ]; do
|
||||
printf '\033['"$1"'m'
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
# Print
|
||||
p() {
|
||||
echo -n "$@"
|
||||
}
|
||||
|
||||
# Print with newline
|
||||
pn() {
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
# For practical reasons, sandwich black and white in-between the other colors.
|
||||
FORE_COLORS="31 30 37 32 33 34 35 36"
|
||||
BACK_COLORS="41 40 47 42 43 44 45 46"
|
||||
|
||||
|
||||
|
||||
### Test order of Invert(7) -- it does not matter what order it appears in.
|
||||
|
||||
# The Red color setting here (31) is shadowed by the green setting (32). The
|
||||
# Reverse flag does not cause (32) to alter the background color immediately;
|
||||
# instead, the Reverse flag is applied once to determine the final effective
|
||||
# Fore/Back colors.
|
||||
s 7 31 32; p " -- Should be: $BACK-on-green -- "; s; pn
|
||||
s 31 7 32; p " -- Should be: $BACK-on-green -- "; s; pn
|
||||
s 31 32 7; p " -- Should be: $BACK-on-green -- "; s; pn
|
||||
|
||||
# As above, but for the background color.
|
||||
s 7 41 42; p " -- Should be: green-on-$FORE -- "; s; pn
|
||||
s 41 7 42; p " -- Should be: green-on-$FORE -- "; s; pn
|
||||
s 41 42 7; p " -- Should be: green-on-$FORE -- "; s; pn
|
||||
|
||||
# One last, related test
|
||||
s 7; p "Invert text"; s 7 1; p " with some words bold"; s; pn;
|
||||
s 0; p "Normal text"; s 0 1; p " with some words bold"; s; pn;
|
||||
|
||||
pn
|
||||
|
||||
|
||||
|
||||
### Test effect of Bold(1) on color, with and without Invert(7).
|
||||
|
||||
# The Bold flag does not affect the background color when Reverse is missing.
|
||||
# There should always be 8 colored boxes.
|
||||
p " "
|
||||
for x in $BACK_COLORS; do
|
||||
s $x; p "-"; s $x 1; p "-"
|
||||
done
|
||||
s; pn " Bold should not affect background"
|
||||
|
||||
# On some terminals, Bold affects color, and on some it doesn't. If there
|
||||
# are only 8 colored boxes, then the next two tests will also show 8 colored
|
||||
# boxes. If there are 16 boxes, then exactly one of the next two tests will
|
||||
# also have 16 boxes.
|
||||
p " "
|
||||
for x in $FORE_COLORS; do
|
||||
s $x; p "$FILL"; s $x 1; p "$FILL"
|
||||
done
|
||||
s; pn " Does bold affect foreground color?"
|
||||
|
||||
# On some terminals, Bold+Invert highlights the final Background color.
|
||||
p " "
|
||||
for x in $FORE_COLORS; do
|
||||
s $x 7; p "-"; s $x 7 1; p "-"
|
||||
done
|
||||
s; pn " Test if Bold+Invert affects background color"
|
||||
|
||||
# On some terminals, Bold+Invert highlights the final Foreground color.
|
||||
p " "
|
||||
for x in $BACK_COLORS; do
|
||||
s $x 7; p "$FILL"; s $x 7 1; p "$FILL"
|
||||
done
|
||||
s; pn " Test if Bold+Invert affects foreground color"
|
||||
|
||||
pn
|
||||
|
||||
|
||||
|
||||
### Test for support of ForeHi and BackHi properties.
|
||||
|
||||
# ForeHi
|
||||
p " "
|
||||
for x in $FORE_COLORS; do
|
||||
hi=$(( $x + 60 ))
|
||||
s $x; p "$FILL"; s $hi; p "$FILL"
|
||||
done
|
||||
s; pn " Test for support of ForeHi colors"
|
||||
p " "
|
||||
for x in $FORE_COLORS; do
|
||||
hi=$(( $x + 60 ))
|
||||
s $x; p "$FILL"; s $x $hi; p "$FILL"
|
||||
done
|
||||
s; pn " Test for support of ForeHi colors (w/compat)"
|
||||
|
||||
# BackHi
|
||||
p " "
|
||||
for x in $BACK_COLORS; do
|
||||
hi=$(( $x + 60 ))
|
||||
s $x; p "-"; s $hi; p "-"
|
||||
done
|
||||
s; pn " Test for support of BackHi colors"
|
||||
p " "
|
||||
for x in $BACK_COLORS; do
|
||||
hi=$(( $x + 60 ))
|
||||
s $x; p "-"; s $x $hi; p "-"
|
||||
done
|
||||
s; pn " Test for support of BackHi colors (w/compat)"
|
||||
|
||||
pn
|
||||
|
||||
|
||||
|
||||
### Identify the default fore and back colors.
|
||||
|
||||
pn "Match default fore and back colors against 16-color palette"
|
||||
pn " ==fore== ==back=="
|
||||
for fore in $FORE_COLORS; do
|
||||
forehi=$(( $fore + 60 ))
|
||||
back=$(( $fore + 10 ))
|
||||
backhi=$(( $back + 60 ))
|
||||
p " "
|
||||
s $fore; p "$FILL"; s; p "$FILL"; s $fore; p "$FILL"; s; p " "
|
||||
s $forehi; p "$FILL"; s; p "$FILL"; s $forehi; p "$FILL"; s; p " "
|
||||
s $back; p "-"; s; p "-"; s $back; p "-"; s; p " "
|
||||
s $backhi; p "-"; s; p "-"; s $backhi; p "-"; s; p " "
|
||||
pn " $fore $forehi $back $backhi"
|
||||
done
|
||||
|
||||
pn
|
||||
|
||||
|
||||
|
||||
### Test coloring of rest-of-line.
|
||||
|
||||
#
|
||||
# When a new line is scrolled in, every cell in the line receives the
|
||||
# current background color, which can be the default/transparent color.
|
||||
#
|
||||
|
||||
p "Newline with red background: usually no red -->"; s 41; pn
|
||||
s; pn "This text is plain, but rest is red if scrolled -->"
|
||||
s; p " "; s 41; printf '\033[1K'; s; printf '\033[1C'; pn "<-- red Erase-in-Line to beginning"
|
||||
s; p "red Erase-in-Line to end -->"; s 41; printf '\033[0K'; s; pn
|
||||
pn
|
||||
|
||||
|
||||
|
||||
### Moving the cursor around does not change colors of anything.
|
||||
|
||||
pn "Test modifying uncolored lines with a colored SGR:"
|
||||
pn "aaaa"
|
||||
pn
|
||||
pn "____e"
|
||||
s 31 42; printf '\033[4C\033[3A'; pn "bb"
|
||||
pn "cccc"
|
||||
pn "dddd"
|
||||
s; pn
|
||||
|
||||
pn "Test modifying colored+inverted+bold line with plain text:"
|
||||
s 42 31 7 1; printf 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r';
|
||||
s; pn "This text is plain and followed by green-on-red -->"
|
||||
pn
|
||||
|
||||
|
||||
|
||||
### Full-width character overwriting
|
||||
|
||||
pn 'Overwrite part of a full-width char with a half-width char'
|
||||
p 'initial U+4000 ideographs -->'; s 31 42; p '䀀䀀'; s; pn
|
||||
p 'write X to index #1 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[24G'; p X; s; pn
|
||||
p 'write X to index #2 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[25G'; p X; s; pn
|
||||
p 'write X to index #3 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[26G'; p X; s; pn
|
||||
p 'write X to index #4 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[27G'; p X; s; pn
|
||||
pn
|
||||
|
||||
pn 'Verify that Erase-in-Line can "fix" last char in line'
|
||||
p 'original -->'; s 31 42; p '䀀䀀'; s; pn
|
||||
p 'overwrite -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[30G'; p 'XXX'; s; pn
|
||||
p 'overwrite + Erase-in-Line -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[30G'; p 'XXX'; s; printf '\033[0K'; pn
|
||||
p 'original -->'; s 31 42; p 'X䀀䀀'; s; pn
|
||||
p 'overwrite -->'; s 31 42; p 'X䀀䀀'; s 35 44; printf '\033[30G'; p 'ーー'; s; pn
|
||||
p 'overwrite + Erase-in-Line -->'; s 31 42; p 'X䀀䀀'; s 35 44; printf '\033[30G'; p 'ーー'; s; printf '\033[0K'; pn
|
||||
pn
|
@ -1,300 +0,0 @@
|
||||
==================================================================
|
||||
Notes regarding fonts, code pages, and East Asian character widths
|
||||
==================================================================
|
||||
|
||||
|
||||
Registry settings
|
||||
=================
|
||||
|
||||
* There are console registry settings in `HKCU\Console`. That key has many
|
||||
default settings (e.g. the default font settings) and also per-app subkeys
|
||||
for app-specific overrides.
|
||||
|
||||
* It is possible to override the code page with an app-specific setting.
|
||||
|
||||
* There are registry settings in
|
||||
`HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console`. In particular,
|
||||
the `TrueTypeFont` subkey has a list of suitable font names associated with
|
||||
various CJK code pages, as well as default font names.
|
||||
|
||||
* There are two values in `HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage`
|
||||
that specify the current code pages -- `OEMCP` and `ACP`. Setting the
|
||||
system locale via the Control Panel's "Region" or "Language" dialogs seems
|
||||
to change these code page values.
|
||||
|
||||
|
||||
Console fonts
|
||||
=============
|
||||
|
||||
* The `FontFamily` field of `CONSOLE_FONT_INFOEX` has two parts:
|
||||
- The high four bits can be exactly one of the `FF_xxxx` font families:
|
||||
FF_DONTCARE(0x00)
|
||||
FF_ROMAN(0x10)
|
||||
FF_SWISS(0x20)
|
||||
FF_MODERN(0x30)
|
||||
FF_SCRIPT(0x40)
|
||||
FF_DECORATIVE(0x50)
|
||||
- The low four bits are a bitmask:
|
||||
TMPF_FIXED_PITCH(1) -- actually means variable pitch
|
||||
TMPF_VECTOR(2)
|
||||
TMPF_TRUETYPE(4)
|
||||
TMPF_DEVICE(8)
|
||||
|
||||
* Each console has its own independent console font table. The current font
|
||||
is identified with an index into this table. The size of the table is
|
||||
returned by the undocumented `GetNumberOfConsoleFonts` API. It is apparently
|
||||
possible to get the table size without this API, by instead calling
|
||||
`GetConsoleFontSize` on each nonnegative index starting with 0 until the API
|
||||
fails by returning (0, 0).
|
||||
|
||||
* The font table grows dynamically. Each time the console is configured with
|
||||
a previously-unused (FaceName, Size) combination, two entries are added to
|
||||
the font table -- one with normal weight and one with bold weight. Fonts
|
||||
added this way are always TrueType fonts.
|
||||
|
||||
* Initially, the font table appears to contain only raster fonts. For
|
||||
example, on an English Windows 8 installation, here is the initial font
|
||||
table:
|
||||
font 0: 4x6
|
||||
font 1: 6x8
|
||||
font 2: 8x8
|
||||
font 3: 16x8
|
||||
font 4: 5x12
|
||||
font 5: 7x12
|
||||
font 6: 8x12 -- the current font
|
||||
font 7: 16x12
|
||||
font 8: 12x16
|
||||
font 9: 10x18
|
||||
`GetNumberOfConsoleFonts` returns 10, and this table matches the raster font
|
||||
sizes according to the console properties dialog.
|
||||
|
||||
* With a Japanese or Chinese locale, the initial font table appears to contain
|
||||
the sizes applicable to both the East Asian raster font, as well as the
|
||||
sizes for the CP437/CP1252 raster font.
|
||||
|
||||
* The index passed to `SetCurrentConsoleFontEx` apparently has no effect.
|
||||
The undocumented `SetConsoleFont` API, however, accepts *only* a font index,
|
||||
and on Windows 8 English, it switches between all 10 fonts, even font index
|
||||
#0.
|
||||
|
||||
* If the index passed to `SetConsoleFont` identifies a Raster Font
|
||||
incompatible with the current code page, then another Raster Font is
|
||||
activated.
|
||||
|
||||
* Passing "Terminal" to `SetCurrentConsoleFontEx` seems to have no effect.
|
||||
Perhaps relatedly, `SetCurrentConsoleFontEx` does not fail if it is given a
|
||||
bogus `FaceName`. Some font is still chosen and activated. Passing a face
|
||||
name and height seems to work reliably, modulo the CP936 issue described
|
||||
below.
|
||||
|
||||
|
||||
Console fonts and code pages
|
||||
============================
|
||||
|
||||
* On an English Windows installation, the default code page is 437, and it
|
||||
cannot be set to 932 (Shift-JIS). (The API call fails.) Changing the
|
||||
system locale to "Japanese (Japan)" using the Region/Language dialog
|
||||
changes the default CP to 932 and permits changing the console CP between
|
||||
437 and 932.
|
||||
|
||||
* A console has both an input code page and an output code page
|
||||
(`{Get,Set}ConsoleCP` and `{Get,Set}ConsoleOutputCP`). I'm not going to
|
||||
distinguish between the two for this document; presumably only the output
|
||||
CP matters. The code page can change while the console is open, e.g.
|
||||
by running `mode con: cp select={932,437,1252}` or by calling
|
||||
`SetConsoleOutputCP`.
|
||||
|
||||
* The current code page restricts which TrueType fonts and which Raster Font
|
||||
sizes are available in the console properties dialog. This can change
|
||||
while the console is open.
|
||||
|
||||
* Changing the code page almost(?) always changes the current console font.
|
||||
So far, I don't know how the new font is chosen.
|
||||
|
||||
* With a CP of 932, the only TrueType font available in the console properties
|
||||
dialog is "MS Gothic", displayed as "MS ゴシック". It is still possible to
|
||||
use the English-default TrueType console fonts, Lucida Console and Consolas,
|
||||
via `SetCurrentConsoleFontEx`.
|
||||
|
||||
* When using a Raster Font and CP437 or CP1252, writing a UTF-16 codepoint not
|
||||
representable in the code page instead writes a question mark ('?') to the
|
||||
console. This conversion does not apply with a TrueType font, nor with the
|
||||
Raster Font for CP932 or CP936.
|
||||
|
||||
|
||||
ReadConsoleOutput and double-width characters
|
||||
==============================================
|
||||
|
||||
* With a Raster Font active, when `ReadConsoleOutputW` reads two cells of a
|
||||
double-width character, it fills only a single `CHAR_INFO` structure. The
|
||||
unused trailing `CHAR_INFO` structures are zero-filled. With a TrueType
|
||||
font active, `ReadConsoleOutputW` instead fills two `CHAR_INFO` structures,
|
||||
the first marked with `COMMON_LVB_LEADING_BYTE` and the second marked with
|
||||
`COMMON_LVB_TRAILING_BYTE`. The flag is a misnomer--there aren't two
|
||||
*bytes*, but two cells, and they have equal `CHAR_INFO.Char.UnicodeChar`
|
||||
values.
|
||||
|
||||
* `ReadConsoleOutputA`, on the other hand, reads two `CHAR_INFO` cells, and
|
||||
if the UTF-16 value can be represented as two bytes in the ANSI/OEM CP, then
|
||||
the two bytes are placed in the two `CHAR_INFO.Char.AsciiChar` values, and
|
||||
the `COMMON_LVB_{LEADING,TRAILING}_BYTE` values are also used. If the
|
||||
codepoint isn't representable, I don't remember what happens -- I think the
|
||||
`AsciiChar` values take on an invalid marker.
|
||||
|
||||
* Reading only one cell of a double-width character reads a space (U+0020)
|
||||
instead. Raster-vs-TrueType and wide-vs-ANSI do not matter.
|
||||
- XXX: what about attributes? Can a double-width character have mismatched
|
||||
color attributes?
|
||||
- XXX: what happens when writing to just one cell of a double-width
|
||||
character?
|
||||
|
||||
|
||||
Default Windows fonts for East Asian languages
|
||||
==============================================
|
||||
CP932 / Japanese: "MS ゴシック" (MS Gothic)
|
||||
CP936 / Chinese Simplified: "新宋体" (SimSun)
|
||||
|
||||
|
||||
Unreliable character width (half-width vs full-width)
|
||||
=====================================================
|
||||
|
||||
The half-width vs full-width status of a codepoint depends on at least these variables:
|
||||
* OS version (Win10 legacy and new modes are different versions)
|
||||
* system locale (English vs Japanese vs Chinese Simplified vs Chinese Traditional, etc)
|
||||
* code page (437 vs 932 vs 936, etc)
|
||||
* raster vs TrueType (Terminal vs MS Gothic vs SimSun, etc)
|
||||
* font size
|
||||
* rendered-vs-model (rendered width can be larger or smaller than model width)
|
||||
|
||||
Example 1: U+2014 (EM DASH): East_Asian_Width: Ambiguous
|
||||
--------------------------------------------------------
|
||||
rendered modeled
|
||||
CP932: Win7/8 Raster Fonts half half
|
||||
CP932: Win7/8 Gothic 14/15px half full
|
||||
CP932: Win7/8 Consolas 14/15px half full
|
||||
CP932: Win7/8 Lucida Console 14px half full
|
||||
CP932: Win7/8 Lucida Console 15px half half
|
||||
CP932: Win10New Raster Fonts half half
|
||||
CP932: Win10New Gothic 14/15px half half
|
||||
CP932: Win10New Consolas 14/15px half half
|
||||
CP932: Win10New Lucida Console 14/15px half half
|
||||
|
||||
CP936: Win7/8 Raster Fonts full full
|
||||
CP936: Win7/8 SimSun 14px full full
|
||||
CP936: Win7/8 SimSun 15px full half
|
||||
CP936: Win7/8 Consolas 14/15px half full
|
||||
CP936: Win10New Raster Fonts full full
|
||||
CP936: Win10New SimSum 14/15px full full
|
||||
CP936: Win10New Consolas 14/15px half half
|
||||
|
||||
Example 2: U+3044 (HIRAGANA LETTER I): East_Asian_Width: Wide
|
||||
-------------------------------------------------------------
|
||||
rendered modeled
|
||||
CP932: Win7/8/10N Raster Fonts full full
|
||||
CP932: Win7/8/10N Gothic 14/15px full full
|
||||
CP932: Win7/8/10N Consolas 14/15px half(*2) full
|
||||
CP932: Win7/8/10N Lucida Console 14/15px half(*3) full
|
||||
|
||||
CP936: Win7/8/10N Raster Fonts full full
|
||||
CP936: Win7/8/10N SimSun 14/15px full full
|
||||
CP936: Win7/8/10N Consolas 14/15px full full
|
||||
|
||||
Example 3: U+30FC (KATAKANA-HIRAGANA PROLONGED SOUND MARK): East_Asian_Width: Wide
|
||||
----------------------------------------------------------------------------------
|
||||
rendered modeled
|
||||
CP932: Win7 Raster Fonts full full
|
||||
CP932: Win7 Gothic 14/15px full full
|
||||
CP932: Win7 Consolas 14/15px half(*2) full
|
||||
CP932: Win7 Lucida Console 14px half(*3) full
|
||||
CP932: Win7 Lucida Console 15px half(*3) half
|
||||
CP932: Win8 Raster Fonts full full
|
||||
CP932: Win8 Gothic 14px full half
|
||||
CP932: Win8 Gothic 15px full full
|
||||
CP932: Win8 Consolas 14/15px half(*2) full
|
||||
CP932: Win8 Lucida Console 14px half(*3) full
|
||||
CP932: Win8 Lucida Console 15px half(*3) half
|
||||
CP932: Win10New Raster Fonts full full
|
||||
CP932: Win10New Gothic 14/15px full full
|
||||
CP932: Win10New Consolas 14/15px half(*2) half
|
||||
CP932: Win10New Lucida Console 14/15px half(*2) half
|
||||
|
||||
CP936: Win7/8 Raster Fonts full full
|
||||
CP936: Win7/8 SimSun 14px full full
|
||||
CP936: Win7/8 SimSun 15px full half
|
||||
CP936: Win7/8 Consolas 14px full full
|
||||
CP936: Win7/8 Consolas 15px full half
|
||||
CP936: Win10New Raster Fonts full full
|
||||
CP936: Win10New SimSum 14/15px full full
|
||||
CP936: Win10New Consolas 14/15px full full
|
||||
|
||||
Example 4: U+4000 (CJK UNIFIED IDEOGRAPH-4000): East_Asian_Width: Wide
|
||||
----------------------------------------------------------------------
|
||||
rendered modeled
|
||||
CP932: Win7 Raster Fonts half(*1) half
|
||||
CP932: Win7 Gothic 14/15px full full
|
||||
CP932: Win7 Consolas 14/15px half(*2) full
|
||||
CP932: Win7 Lucida Console 14px half(*3) full
|
||||
CP932: Win7 Lucida Console 15px half(*3) half
|
||||
CP932: Win8 Raster Fonts half(*1) half
|
||||
CP932: Win8 Gothic 14px full half
|
||||
CP932: Win8 Gothic 15px full full
|
||||
CP932: Win8 Consolas 14/15px half(*2) full
|
||||
CP932: Win8 Lucida Console 14px half(*3) full
|
||||
CP932: Win8 Lucida Console 15px half(*3) half
|
||||
CP932: Win10New Raster Fonts half(*1) half
|
||||
CP932: Win10New Gothic 14/15px full full
|
||||
CP932: Win10New Consolas 14/15px half(*2) half
|
||||
CP932: Win10New Lucida Console 14/15px half(*2) half
|
||||
|
||||
CP936: Win7/8 Raster Fonts full full
|
||||
CP936: Win7/8 SimSun 14px full full
|
||||
CP936: Win7/8 SimSun 15px full half
|
||||
CP936: Win7/8 Consolas 14px full full
|
||||
CP936: Win7/8 Consolas 15px full half
|
||||
CP936: Win10New Raster Fonts full full
|
||||
CP936: Win10New SimSum 14/15px full full
|
||||
CP936: Win10New Consolas 14/15px full full
|
||||
|
||||
(*1) Rendered as a half-width filled white box
|
||||
(*2) Rendered as a half-width box with a question mark inside
|
||||
(*3) Rendered as a half-width empty box
|
||||
(!!) One of the only places in Win10New where rendered and modeled width disagree
|
||||
|
||||
|
||||
Windows quirk: unreliable font heights with CP936 / Chinese Simplified
|
||||
======================================================================
|
||||
|
||||
When I set the font to 新宋体 17px, using either the properties dialog or
|
||||
`SetCurrentConsoleFontEx`, the height reported by `GetCurrentConsoleFontEx` is
|
||||
not 17, but is instead 19. The same problem does not affect Raster Fonts,
|
||||
nor have I seen the problem in the English or Japanese locales. I observed
|
||||
this with Windows 7 and Windows 10 new mode.
|
||||
|
||||
If I set the font using the facename, width, *and* height, then the
|
||||
`SetCurrentConsoleFontEx` and `GetCurrentConsoleFontEx` values agree. If I
|
||||
set the font using *only* the facename and height, then the two values
|
||||
disagree.
|
||||
|
||||
|
||||
Windows bug: GetCurrentConsoleFontEx is initially invalid
|
||||
=========================================================
|
||||
|
||||
- Assume there is no configured console font name in the registry. In this
|
||||
case, the console defaults to a raster font.
|
||||
- Open a new console and call the `GetCurrentConsoleFontEx` API.
|
||||
- The `FaceName` field of the returned `CONSOLE_FONT_INFOEX` data
|
||||
structure is incorrect. On Windows 7, 8, and 10, I observed that the
|
||||
field was blank. On Windows 8, occasionally, it instead contained:
|
||||
U+AE72 U+75BE U+0001
|
||||
The other fields of the structure all appeared correct:
|
||||
nFont=6 dwFontSize=(8,12) FontFamily=0x30 FontWeight=400
|
||||
- The `FaceName` field becomes initialized easily:
|
||||
- Open the console properties dialog and click OK. (Cancel is not
|
||||
sufficient.)
|
||||
- Call the undocumented `SetConsoleFont` with the current font table
|
||||
index, which is 6 in the example above.
|
||||
- It seems that the console uncritically accepts whatever string is
|
||||
stored in the registry, including a blank string, and passes it on the
|
||||
the `GetCurrentConsoleFontEx` caller. It is possible to get the console
|
||||
to *write* a blank setting into the registry -- simply open the console
|
||||
(default or app-specific) properties and click OK.
|
@ -1,201 +0,0 @@
|
||||
/*
|
||||
|
||||
Test program demonstrating a problem in Windows 15048's ReadConsoleOutput API.
|
||||
|
||||
To compile:
|
||||
|
||||
cl /nologo /EHsc winbug-15048.cc shell32.lib
|
||||
|
||||
Example of regressed input:
|
||||
|
||||
Case 1:
|
||||
|
||||
> chcp 932
|
||||
> winbug-15048 -face-gothic 3044
|
||||
|
||||
Correct output:
|
||||
|
||||
1**34 (nb: U+3044 replaced with '**' to avoid MSVC encoding warning)
|
||||
5678
|
||||
|
||||
ReadConsoleOutputW (both rows, 3 cols)
|
||||
row 0: U+0031(0007) U+3044(0107) U+3044(0207) U+0033(0007)
|
||||
row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007)
|
||||
|
||||
ReadConsoleOutputW (both rows, 4 cols)
|
||||
row 0: U+0031(0007) U+3044(0107) U+3044(0207) U+0033(0007) U+0034(0007)
|
||||
row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007)
|
||||
|
||||
ReadConsoleOutputW (second row)
|
||||
row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007)
|
||||
|
||||
...
|
||||
|
||||
Win10 15048 bad output:
|
||||
|
||||
1**34
|
||||
5678
|
||||
|
||||
ReadConsoleOutputW (both rows, 3 cols)
|
||||
row 0: U+0031(0007) U+3044(0007) U+0033(0007) U+0035(0007)
|
||||
row 1: U+0036(0007) U+0037(0007) U+0038(0007) U+0000(0000)
|
||||
|
||||
ReadConsoleOutputW (both rows, 4 cols)
|
||||
row 0: U+0031(0007) U+3044(0007) U+0033(0007) U+0034(0007) U+0035(0007)
|
||||
row 1: U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007) U+0000(0000)
|
||||
|
||||
ReadConsoleOutputW (second row)
|
||||
row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007)
|
||||
|
||||
...
|
||||
|
||||
The U+3044 character (HIRAGANA LETTER I) occupies two columns, but it only
|
||||
fills one record in the ReadConsoleOutput output buffer, which has the
|
||||
effect of shifting the first cell of the second row into the last cell of
|
||||
the first row. Ordinarily, the first and second cells would also have the
|
||||
COMMON_LVB_LEADING_BYTE and COMMON_LVB_TRAILING_BYTE attributes set, which
|
||||
allows winpty to detect the double-column character.
|
||||
|
||||
Case 2:
|
||||
|
||||
> chcp 437
|
||||
> winbug-15048 -face "Lucida Console" -h 4 221A
|
||||
|
||||
The same issue happens with U+221A (SQUARE ROOT), but only in certain
|
||||
fonts. The console seems to think this character occupies two columns
|
||||
if the font is sufficiently small. The Windows console properties dialog
|
||||
doesn't allow fonts below 5 pt, but winpty tries to use 2pt and 4pt Lucida
|
||||
Console to allow very large console windows.
|
||||
|
||||
Case 3:
|
||||
|
||||
> chcp 437
|
||||
> winbug-15048 -face "Lucida Console" -h 12 FF12
|
||||
|
||||
The console selection system thinks U+FF12 (FULLWIDTH DIGIT TWO) occupies
|
||||
two columns, which happens to be correct, but it's displayed as a single
|
||||
column unrecognized character. It otherwise behaves the same as the other
|
||||
cases.
|
||||
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
|
||||
static void set_font(const wchar_t *name, int size) {
|
||||
const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_FONT_INFOEX fontex {};
|
||||
fontex.cbSize = sizeof(fontex);
|
||||
fontex.dwFontSize.Y = size;
|
||||
fontex.FontWeight = 400;
|
||||
fontex.FontFamily = 0x36;
|
||||
wcsncpy(fontex.FaceName, name, COUNT_OF(fontex.FaceName));
|
||||
assert(SetCurrentConsoleFontEx(conout, FALSE, &fontex));
|
||||
}
|
||||
|
||||
static void usage(const wchar_t *prog) {
|
||||
printf("Usage: %ls [options]\n", prog);
|
||||
printf(" -h HEIGHT\n");
|
||||
printf(" -face FACENAME\n");
|
||||
printf(" -face-{gothic|simsun|minglight|gulimche) [JP,CN-sim,CN-tra,KR]\n");
|
||||
printf(" hhhh -- print U+hhhh\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void dump_region(SMALL_RECT region, const char *name) {
|
||||
const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
CHAR_INFO buf[1000];
|
||||
memset(buf, 0xcc, sizeof(buf));
|
||||
|
||||
const int w = region.Right - region.Left + 1;
|
||||
const int h = region.Bottom - region.Top + 1;
|
||||
|
||||
assert(ReadConsoleOutputW(
|
||||
conout, buf, { (short)w, (short)h }, { 0, 0 },
|
||||
®ion));
|
||||
|
||||
printf("\n");
|
||||
printf("ReadConsoleOutputW (%s)\n", name);
|
||||
for (int y = 0; y < h; ++y) {
|
||||
printf("row %d: ", region.Top + y);
|
||||
for (int i = 0; i < region.Left * 13; ++i) {
|
||||
printf(" ");
|
||||
}
|
||||
for (int x = 0; x < w; ++x) {
|
||||
const int i = y * w + x;
|
||||
printf("U+%04x(%04x) ", buf[i].Char.UnicodeChar, buf[i].Attributes);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
wchar_t *cmdline = GetCommandLineW();
|
||||
int argc = 0;
|
||||
wchar_t **argv = CommandLineToArgvW(cmdline, &argc);
|
||||
const wchar_t *font_name = L"Lucida Console";
|
||||
int font_height = 8;
|
||||
int test_ch = 0xff12; // U+FF12 FULLWIDTH DIGIT TWO
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
const std::wstring arg = argv[i];
|
||||
const std::wstring next = i + 1 < argc ? argv[i + 1] : L"";
|
||||
if (arg == L"-face" && i + 1 < argc) {
|
||||
font_name = argv[i + 1];
|
||||
i++;
|
||||
} else if (arg == L"-face-gothic") {
|
||||
font_name = kMSGothic;
|
||||
} else if (arg == L"-face-simsun") {
|
||||
font_name = kNSimSun;
|
||||
} else if (arg == L"-face-minglight") {
|
||||
font_name = kMingLight;
|
||||
} else if (arg == L"-face-gulimche") {
|
||||
font_name = kGulimChe;
|
||||
} else if (arg == L"-h" && i + 1 < argc) {
|
||||
font_height = _wtoi(next.c_str());
|
||||
i++;
|
||||
} else if (arg.c_str()[0] != '-') {
|
||||
test_ch = wcstol(arg.c_str(), NULL, 16);
|
||||
} else {
|
||||
printf("Unrecognized argument: %ls\n", arg.c_str());
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
set_font(font_name, font_height);
|
||||
|
||||
system("cls");
|
||||
DWORD actual = 0;
|
||||
wchar_t output[] = L"1234\n5678\n";
|
||||
output[1] = test_ch;
|
||||
WriteConsoleW(conout, output, 10, &actual, nullptr);
|
||||
|
||||
dump_region({ 0, 0, 3, 1 }, "both rows, 3 cols");
|
||||
dump_region({ 0, 0, 4, 1 }, "both rows, 4 cols");
|
||||
dump_region({ 0, 1, 4, 1 }, "second row");
|
||||
dump_region({ 0, 0, 4, 0 }, "first row");
|
||||
dump_region({ 1, 0, 4, 0 }, "first row, skip 1");
|
||||
dump_region({ 2, 0, 4, 0 }, "first row, skip 2");
|
||||
dump_region({ 3, 0, 4, 0 }, "first row, skip 3");
|
||||
|
||||
set_font(font_name, 14);
|
||||
|
||||
return 0;
|
||||
}
|
@ -18,21 +18,17 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef WINPTY_SHARED_AGENT_MSG_H
|
||||
#define WINPTY_SHARED_AGENT_MSG_H
|
||||
#ifndef AGENTMSG_H
|
||||
#define AGENTMSG_H
|
||||
|
||||
struct AgentMsg
|
||||
{
|
||||
enum Type {
|
||||
Ping,
|
||||
StartProcess,
|
||||
SetSize,
|
||||
GetConsoleProcessList,
|
||||
GetExitCode
|
||||
};
|
||||
};
|
||||
|
||||
enum class StartProcessResult {
|
||||
CreateProcessFailed,
|
||||
ProcessCreated,
|
||||
};
|
||||
|
||||
#endif // WINPTY_SHARED_AGENT_MSG_H
|
||||
#endif // AGENTMSG_H
|
99
shared/Buffer.h
Normal file
99
shared/Buffer.h
Normal file
@ -0,0 +1,99 @@
|
||||
// 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.
|
||||
|
||||
#ifndef BUFFER_H
|
||||
#define BUFFER_H
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
class WriteBuffer
|
||||
{
|
||||
private:
|
||||
std::stringstream ss;
|
||||
public:
|
||||
void putInt(int i);
|
||||
void putWString(const std::wstring &str);
|
||||
void putWString(const wchar_t *str);
|
||||
std::string str() const;
|
||||
};
|
||||
|
||||
inline void WriteBuffer::putInt(int i)
|
||||
{
|
||||
ss.write((const char*)&i, sizeof(i));
|
||||
}
|
||||
|
||||
inline void WriteBuffer::putWString(const std::wstring &str)
|
||||
{
|
||||
putInt(str.size());
|
||||
ss.write((const char*)str.c_str(), sizeof(wchar_t) * str.size());
|
||||
}
|
||||
|
||||
inline void WriteBuffer::putWString(const wchar_t *str)
|
||||
{
|
||||
int len = wcslen(str);
|
||||
putInt(len);
|
||||
ss.write((const char*)str, sizeof(wchar_t) * len);
|
||||
}
|
||||
|
||||
inline std::string WriteBuffer::str() const
|
||||
{
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
class ReadBuffer
|
||||
{
|
||||
private:
|
||||
std::stringstream ss;
|
||||
public:
|
||||
ReadBuffer(const std::string &packet);
|
||||
int getInt();
|
||||
std::wstring getWString();
|
||||
bool eof();
|
||||
};
|
||||
|
||||
inline ReadBuffer::ReadBuffer(const std::string &packet) : ss(packet)
|
||||
{
|
||||
}
|
||||
|
||||
inline int ReadBuffer::getInt()
|
||||
{
|
||||
int i;
|
||||
ss.read((char*)&i, sizeof(i));
|
||||
return i;
|
||||
}
|
||||
|
||||
inline std::wstring ReadBuffer::getWString()
|
||||
{
|
||||
int len = getInt();
|
||||
wchar_t *tmp = new wchar_t[len];
|
||||
ss.read((char*)tmp, sizeof(wchar_t) * len);
|
||||
std::wstring ret(tmp, len);
|
||||
delete [] tmp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline bool ReadBuffer::eof()
|
||||
{
|
||||
ss.peek();
|
||||
return ss.eof();
|
||||
}
|
||||
|
||||
#endif /* BUFFER_H */
|
102
shared/DebugClient.cc
Normal file
102
shared/DebugClient.cc
Normal file
@ -0,0 +1,102 @@
|
||||
// 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.
|
||||
|
||||
#include "DebugClient.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "c99_snprintf.h"
|
||||
|
||||
char *tracingConfig;
|
||||
|
||||
static void sendToDebugServer(const char *message)
|
||||
{
|
||||
char response[16];
|
||||
DWORD responseSize;
|
||||
CallNamedPipeA(
|
||||
"\\\\.\\pipe\\DebugServer",
|
||||
(void*)message, strlen(message),
|
||||
response, sizeof(response), &responseSize,
|
||||
NMPWAIT_WAIT_FOREVER);
|
||||
}
|
||||
|
||||
// Get the current UTC time as milliseconds from the epoch (ignoring leap
|
||||
// seconds). Use the Unix epoch for consistency with DebugClient.py. There
|
||||
// are 134774 days between 1601-01-01 (the Win32 epoch) and 1970-01-01 (the
|
||||
// Unix epoch).
|
||||
static long long unixTimeMillis()
|
||||
{
|
||||
FILETIME fileTime;
|
||||
GetSystemTimeAsFileTime(&fileTime);
|
||||
long long msTime = (((long long)fileTime.dwHighDateTime << 32) +
|
||||
fileTime.dwLowDateTime) / 10000;
|
||||
return msTime - 134774LL * 24 * 3600 * 1000;
|
||||
}
|
||||
|
||||
static const char *getTracingConfig()
|
||||
{
|
||||
if (tracingConfig == NULL) {
|
||||
const int bufSize = 256;
|
||||
char buf[bufSize];
|
||||
DWORD actualSize = GetEnvironmentVariableA("WINPTYDBG", buf, bufSize);
|
||||
if (actualSize == 0 || actualSize >= (DWORD)bufSize)
|
||||
buf[0] = '\0';
|
||||
tracingConfig = new char[strlen(buf) + 1];
|
||||
strcpy(tracingConfig, buf);
|
||||
}
|
||||
return tracingConfig;
|
||||
}
|
||||
|
||||
bool isTracingEnabled()
|
||||
{
|
||||
return getTracingConfig()[0] != '\0';
|
||||
}
|
||||
|
||||
void trace(const char *format, ...)
|
||||
{
|
||||
if (!isTracingEnabled())
|
||||
return;
|
||||
|
||||
char message[1024];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
c99_vsnprintf(message, sizeof(message), format, ap);
|
||||
message[sizeof(message) - 1] = '\0';
|
||||
va_end(ap);
|
||||
|
||||
const int currentTime = (int)(unixTimeMillis() % (100000 * 1000));
|
||||
|
||||
char moduleName[1024];
|
||||
moduleName[0] = '\0';
|
||||
GetModuleFileNameA(NULL, moduleName, sizeof(moduleName));
|
||||
const char *baseName = strrchr(moduleName, '\\');
|
||||
baseName = (baseName != NULL) ? baseName + 1 : moduleName;
|
||||
|
||||
char fullMessage[1024];
|
||||
c99_snprintf(fullMessage, sizeof(fullMessage),
|
||||
"[%05d.%03d %s,p%04d,t%04d]: %s",
|
||||
currentTime / 1000, currentTime % 1000,
|
||||
baseName, (int)GetCurrentProcessId(), (int)GetCurrentThreadId(),
|
||||
message);
|
||||
fullMessage[sizeof(fullMessage) - 1] = '\0';
|
||||
|
||||
sendToDebugServer(fullMessage);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2015 Ryan Prichard
|
||||
// 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
|
||||
@ -18,11 +18,10 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef CONSOLEFONT_H
|
||||
#define CONSOLEFONT_H
|
||||
#ifndef DEBUGCLIENT_H
|
||||
#define DEBUGCLIENT_H
|
||||
|
||||
#include <windows.h>
|
||||
bool isTracingEnabled();
|
||||
void trace(const char *format, ...);
|
||||
|
||||
void setSmallFont(HANDLE conout, int columns, bool isNewW10);
|
||||
|
||||
#endif // CONSOLEFONT_H
|
||||
#endif // DEBUGCLIENT_H
|
87
shared/c99_snprintf.h
Normal file
87
shared/c99_snprintf.h
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright (c) 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.
|
||||
|
||||
#ifndef C99_SNPRINTF_H
|
||||
#define C99_SNPRINTF_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
/* MSVC does not define C99's va_copy, so define one for it. It appears that
|
||||
* with MSVC, a va_list is a char*, not an array type, so va_copy is a simple
|
||||
* assignment. On MSVC 2012, there is a VC/include/vadefs.h file defining
|
||||
* va_list and the va_XXX routines, which has code for x86, x86-64, and ARM. */
|
||||
#define c99_va_copy(dest, src) ((dest) = (src))
|
||||
|
||||
static inline int c99_vsnprintf(
|
||||
char* str,
|
||||
size_t size,
|
||||
const char* format,
|
||||
va_list ap)
|
||||
{
|
||||
va_list apcopy;
|
||||
int count = -1;
|
||||
if (size != 0) {
|
||||
c99_va_copy(apcopy, ap);
|
||||
count = _vsnprintf_s(str, size, _TRUNCATE, format, apcopy);
|
||||
va_end(apcopy);
|
||||
}
|
||||
if (count == -1) {
|
||||
c99_va_copy(apcopy, ap);
|
||||
count = _vscprintf(format, apcopy);
|
||||
va_end(apcopy);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define c99_va_copy(dest, src) (va_copy(dest, src))
|
||||
|
||||
static inline int c99_vsnprintf(
|
||||
char* str,
|
||||
size_t size,
|
||||
const char* format,
|
||||
va_list ap)
|
||||
{
|
||||
return vsnprintf(str, size, format, ap);
|
||||
}
|
||||
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
static inline int c99_snprintf(
|
||||
char* str,
|
||||
size_t size,
|
||||
const char* format,
|
||||
...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
count = c99_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif /* C99_SNPRINTF_H */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user