This commit is contained in:
Dustin Howett 2019-05-02 17:34:28 -07:00
commit 23f85d01f0
68 changed files with 5506 additions and 13 deletions

13
.github/ISSUE_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,13 @@
This bug-tracker is monitored by Windows Console development team and other technical types. **We like detail!**
If you have a feature request, please post to [the UserVoice](https://wpdev.uservoice.com/forums/266908).
> **Important: When reporting BSODs or security issues, DO NOT attach memory dumps, logs, or traces to Github issues**. Instead, send dumps/traces to secure@microsoft.com, referencing this GitHub issue.
Please use this form and describe your issue, concisely but precisely, with as much detail as possible
* Your Windows build number: (Type `ver` at a Windows Command Prompt)
* What you're doing and what's happening: (Copy & paste specific commands and their output, or include screen shots)
* What's wrong / what should be happening instead:

58
.gitignore vendored
View file

@ -21,6 +21,7 @@ build/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
objfre/
objchk/
@ -79,14 +80,18 @@ _Chutzpah*
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
@ -111,6 +116,7 @@ _TeamCity*
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
@ -138,13 +144,16 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
## TODO: Comment the next line if you want to checkin your
## web deploy settings but do note that will include unencrypted
## passwords
#*.pubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
@ -153,13 +162,23 @@ publish/
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Windows Azure Build Output
# Microsoft Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
@ -211,12 +230,25 @@ FakesAssemblies/
# Visual Studio 6 workspace options file
*.opt
# LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
*.opendb
*.db
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
*.exe
# Windows Build System files
build*.dbb

28
README-ColorTool.md Normal file
View file

@ -0,0 +1,28 @@
# Welcome to the official Windows Console issues & samples repo!
## Issues
This repo is monitored by the Windows Console engineering team, and provides a best-effort, informal support option for the community. Your patience is appreciated!
The Windows Console engineering team greatly appreciate issues containing concise, detailed issues containing repro-steps, and screenshots where appropriate :)
We also appreciate not +1-ing issues with no additional or actionable information. Please use a reaction to show your support of an existing comment on the thread and/or subscribe to notifications using the button in the sidebar in lieu of providing a low-value comment.
### Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact opencode@microsoft.com with any additional questions or comments.
In addition, the team reserve the right to actively manage issues, closing duplicates or resolved issues, etc., and would appreciate it if you would avoid creating duplicates of existing items by searching issues _before_ filing a new issue.
## Tools & Samples
You'll also find assorted Console tools, samples, including the following:
* [ColorTool](https://github.com/Microsoft/Console/tree/master/src/tools/ColorTool) - A tool for changing the color scheme of the Windows console.
* [EchoCon](https://github.com/Microsoft/console/tree/master/samples/ConPTY/EchoCon) - A C++ sample application that illustrates how to use the new Win32 Pseudo Console (ConPTY).
* [MiniTerm](https://github.com/Microsoft/console/tree/master/samples/ConPTY/MiniTerm) - A C# sample terminal that illustrates how to use ConPTY.
* [ReadConsoleInputStream](https://github.com/Microsoft/console/tree/master/samples/ReadConsoleInputStream) - A C# sample console application that shows how to use the console APIs to stream stdin while asynchronously watching for console events (buffer size, viewport size, mouse input etc.)
### Tool Build Status
Project|Build Status
---|---
src/tools/ColorTool|![](https://microsoft.visualstudio.com/_apis/public/build/definitions/c93e867a-8815-43c1-92c4-e7dd5404f1e1/17023/badge)

View file

@ -0,0 +1,36 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2026
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EchoCon", "EchoCon\EchoCon.vcxproj", "{96274800-9574-423E-892A-909FBE2AC8BE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{556CAA54-33E0-4F99-95C8-0DFD6E8F6C6B}"
ProjectSection(SolutionItems) = preProject
readme.md = readme.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{96274800-9574-423E-892A-909FBE2AC8BE}.Debug|x64.ActiveCfg = Debug|x64
{96274800-9574-423E-892A-909FBE2AC8BE}.Debug|x64.Build.0 = Debug|x64
{96274800-9574-423E-892A-909FBE2AC8BE}.Debug|x86.ActiveCfg = Debug|Win32
{96274800-9574-423E-892A-909FBE2AC8BE}.Debug|x86.Build.0 = Debug|Win32
{96274800-9574-423E-892A-909FBE2AC8BE}.Release|x64.ActiveCfg = Release|x64
{96274800-9574-423E-892A-909FBE2AC8BE}.Release|x64.Build.0 = Release|x64
{96274800-9574-423E-892A-909FBE2AC8BE}.Release|x86.ActiveCfg = Release|Win32
{96274800-9574-423E-892A-909FBE2AC8BE}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B27C5007-61E2-4080-965D-8C934367BA4F}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,189 @@
// EchoCon.cpp : Entry point for the EchoCon Pseudo-Consle sample application.
// Copyright © 2018, Microsoft
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
// Forward declarations
HRESULT CreatePseudoConsoleAndPipes(HPCON*, HANDLE*, HANDLE*);
HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX*, HPCON);
void __cdecl PipeListener(LPVOID);
int main()
{
wchar_t szCommand[]{ L"ping localhost" };
HRESULT hr{ E_UNEXPECTED };
HANDLE hConsole = { GetStdHandle(STD_OUTPUT_HANDLE) };
// Enable Console VT Processing
DWORD consoleMode{};
GetConsoleMode(hConsole, &consoleMode);
hr = SetConsoleMode(hConsole, consoleMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
? S_OK
: GetLastError();
if (S_OK == hr)
{
HPCON hPC{ INVALID_HANDLE_VALUE };
// Create the Pseudo Console and pipes to it
HANDLE hPipeIn{ INVALID_HANDLE_VALUE };
HANDLE hPipeOut{ INVALID_HANDLE_VALUE };
hr = CreatePseudoConsoleAndPipes(&hPC, &hPipeIn, &hPipeOut);
if (S_OK == hr)
{
// Create & start thread to listen to the incoming pipe
// Note: Using CRT-safe _beginthread() rather than CreateThread()
HANDLE hPipeListenerThread{ reinterpret_cast<HANDLE>(_beginthread(PipeListener, 0, hPipeIn)) };
// Initialize the necessary startup info struct
STARTUPINFOEX startupInfo{};
if (S_OK == InitializeStartupInfoAttachedToPseudoConsole(&startupInfo, hPC))
{
// Launch ping to emit some text back via the pipe
PROCESS_INFORMATION piClient{};
hr = CreateProcess(
NULL, // No module name - use Command Line
szCommand, // Command Line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Inherit handles
EXTENDED_STARTUPINFO_PRESENT, // Creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startupInfo.StartupInfo, // Pointer to STARTUPINFO
&piClient) // Pointer to PROCESS_INFORMATION
? S_OK
: GetLastError();
if (S_OK == hr)
{
// Wait up to 10s for ping process to complete
WaitForSingleObject(piClient.hThread, 10 * 1000);
// Allow listening thread to catch-up with final output!
Sleep(500);
}
// --- CLOSEDOWN ---
// Now safe to clean-up client app's process-info & thread
CloseHandle(piClient.hThread);
CloseHandle(piClient.hProcess);
// Cleanup attribute list
DeleteProcThreadAttributeList(startupInfo.lpAttributeList);
free(startupInfo.lpAttributeList);
}
// Close ConPTY - this will terminate client process if running
ClosePseudoConsole(hPC);
// Clean-up the pipes
if (INVALID_HANDLE_VALUE != hPipeOut) CloseHandle(hPipeOut);
if (INVALID_HANDLE_VALUE != hPipeIn) CloseHandle(hPipeIn);
}
}
return S_OK == hr ? EXIT_SUCCESS : EXIT_FAILURE;
}
HRESULT CreatePseudoConsoleAndPipes(HPCON* phPC, HANDLE* phPipeIn, HANDLE* phPipeOut)
{
HRESULT hr{ E_UNEXPECTED };
HANDLE hPipePTYIn{ INVALID_HANDLE_VALUE };
HANDLE hPipePTYOut{ INVALID_HANDLE_VALUE };
// Create the pipes to which the ConPTY will connect
if (CreatePipe(&hPipePTYIn, phPipeOut, NULL, 0) &&
CreatePipe(phPipeIn, &hPipePTYOut, NULL, 0))
{
// Determine required size of Pseudo Console
COORD consoleSize{};
CONSOLE_SCREEN_BUFFER_INFO csbi{};
HANDLE hConsole{ GetStdHandle(STD_OUTPUT_HANDLE) };
if (GetConsoleScreenBufferInfo(hConsole, &csbi))
{
consoleSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
consoleSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
}
// Create the Pseudo Console of the required size, attached to the PTY-end of the pipes
hr = CreatePseudoConsole(consoleSize, hPipePTYIn, hPipePTYOut, 0, phPC);
// Note: We can close the handles to the PTY-end of the pipes here
// because the handles are dup'ed into the ConHost and will be released
// when the ConPTY is destroyed.
if (INVALID_HANDLE_VALUE != hPipePTYOut) CloseHandle(hPipePTYOut);
if (INVALID_HANDLE_VALUE != hPipePTYIn) CloseHandle(hPipePTYIn);
}
return hr;
}
// Initializes the specified startup info struct with the required properties and
// updates its thread attribute list with the specified ConPTY handle
HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX* pStartupInfo, HPCON hPC)
{
HRESULT hr{ E_UNEXPECTED };
if (pStartupInfo)
{
size_t attrListSize{};
pStartupInfo->StartupInfo.cb = sizeof(STARTUPINFOEX);
// Get the size of the thread attribute list.
InitializeProcThreadAttributeList(NULL, 1, 0, &attrListSize);
// Allocate a thread attribute list of the correct size
pStartupInfo->lpAttributeList =
reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(malloc(attrListSize));
// Initialize thread attribute list
if (pStartupInfo->lpAttributeList
&& InitializeProcThreadAttributeList(pStartupInfo->lpAttributeList, 1, 0, &attrListSize))
{
// Set Pseudo Console attribute
hr = UpdateProcThreadAttribute(
pStartupInfo->lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
hPC,
sizeof(HPCON),
NULL,
NULL)
? S_OK
: HRESULT_FROM_WIN32(GetLastError());
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
return hr;
}
void __cdecl PipeListener(LPVOID pipe)
{
HANDLE hPipe{ pipe };
HANDLE hConsole{ GetStdHandle(STD_OUTPUT_HANDLE) };
const DWORD BUFF_SIZE{ 512 };
char szBuffer[BUFF_SIZE]{};
DWORD dwBytesWritten{};
DWORD dwBytesRead{};
BOOL fRead{ FALSE };
do
{
// Read from the pipe
fRead = ReadFile(hPipe, szBuffer, BUFF_SIZE, &dwBytesRead, NULL);
// Write received text to the Console
// Note: Write to the Console using WriteFile(hConsole...), not printf()/puts() to
// prevent partially-read VT sequences from corrupting output
WriteFile(hConsole, szBuffer, dwBytesRead, &dwBytesWritten, NULL);
} while (fRead && dwBytesRead >= 0);
}

View file

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{96274800-9574-423E-892A-909FBE2AC8BE}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>EchoCon</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="EchoCon.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="EchoCon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// EchoCon.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View file

@ -0,0 +1,13 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here

View file

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>

View file

@ -0,0 +1,34 @@
# "EchoCon" ConPTY Sample App
This is a very simple sample application that illustrates how to use the new Win32 Pseudo Console
(ConPTY) by:
1. Creating an input and an output pipe
1. Calling `CreatePseudoConsole()` to create a ConPTY instance attached to the other end of the pipes
1. Spawning an instance of `ping.exe` connected to the ConPTY
1. Running a thread that listens for output from ping.exe, writing received text to the Console
# Pre-Requirements
To build and run this sample, you must install:
* Windows 10 Insider build 17733 or later
* [Latest Windows 10 Insider SDK](https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewSDK)
# Running the sample
Once successfully built, running EchoCon should clear the screen and display the results of the
echo command:
```
Pinging Rincewind [::1] with 32 bytes of data:
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Reply from ::1: time<1ms
Ping statistics for ::1:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
```
# Resources
For more information on the new Pseudo Console infrastructure and API, please review
[this blog post](https://blogs.msdn.microsoft.com/commandline/2018/08/02/windows-command-line-introducing-the-windows-pseudo-console-conpty/)

View file

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2035
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniTerm", "MiniTerm\MiniTerm.csproj", "{121D4818-BD57-433B-8AD5-C4E1ACE7E7C0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{121D4818-BD57-433B-8AD5-C4E1ACE7E7C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{121D4818-BD57-433B-8AD5-C4E1ACE7E7C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{121D4818-BD57-433B-8AD5-C4E1ACE7E7C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{121D4818-BD57-433B-8AD5-C4E1ACE7E7C0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EFB13BDE-C952-4311-9FE7-35EFDAC8F021}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{121D4818-BD57-433B-8AD5-C4E1ACE7E7C0}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>MiniTerm</RootNamespace>
<AssemblyName>MiniTerm</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Native\ConsoleApi.cs" />
<Compile Include="Native\ProcessApi.cs" />
<Compile Include="Native\PseudoConsoleApi.cs" />
<Compile Include="Processes\Process.cs" />
<Compile Include="Processes\ProcessFactory.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PseudoConsole.cs" />
<Compile Include="PseudoConsolePipe.cs" />
<Compile Include="Terminal.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,38 @@
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
namespace MiniTerm.Native
{
/// <summary>
/// PInvoke signatures for win32 console api
/// </summary>
static class ConsoleApi
{
internal const int STD_OUTPUT_HANDLE = -11;
internal const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
internal const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008;
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern SafeFileHandle GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetConsoleMode(SafeFileHandle hConsoleHandle, uint mode);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool GetConsoleMode(SafeFileHandle handle, out uint mode);
internal delegate bool ConsoleEventDelegate(CtrlTypes ctrlType);
internal enum CtrlTypes : uint
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
}
}

View file

@ -0,0 +1,86 @@
using System;
using System.Runtime.InteropServices;
namespace MiniTerm.Native
{
/// <summary>
/// PInvoke signatures for win32 process api
/// </summary>
static class ProcessApi
{
internal const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool InitializeProcThreadAttributeList(
IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UpdateProcThreadAttribute(
IntPtr lpAttributeList, uint dwFlags, IntPtr attribute, IntPtr lpValue,
IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CreateProcess(
string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags,
IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteProcThreadAttributeList(IntPtr lpAttributeList);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool CloseHandle(IntPtr hObject);
}
}

View file

@ -0,0 +1,33 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
namespace MiniTerm.Native
{
/// <summary>
/// PInvoke signatures for win32 pseudo console api
/// </summary>
static class PseudoConsoleApi
{
internal const uint PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = 0x00020016;
[StructLayout(LayoutKind.Sequential)]
internal struct COORD
{
public short X;
public short Y;
}
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern int CreatePseudoConsole(COORD size, SafeFileHandle hInput, SafeFileHandle hOutput, uint dwFlags, out IntPtr phPC);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern int ResizePseudoConsole(IntPtr hPC, COORD size);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern int ClosePseudoConsole(IntPtr hPC);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool CreatePipe(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, IntPtr lpPipeAttributes, int nSize);
}
}

View file

@ -0,0 +1,74 @@
using System;
using System.Runtime.InteropServices;
using static MiniTerm.Native.ProcessApi;
namespace MiniTerm
{
/// <summary>
/// Represents an instance of a process.
/// </summary>
internal sealed class Process : IDisposable
{
public Process(STARTUPINFOEX startupInfo, PROCESS_INFORMATION processInfo)
{
StartupInfo = startupInfo;
ProcessInfo = processInfo;
}
public STARTUPINFOEX StartupInfo { get; }
public PROCESS_INFORMATION ProcessInfo { get; }
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// dispose managed state (managed objects).
}
// dispose unmanaged state
// Free the attribute list
if (StartupInfo.lpAttributeList != IntPtr.Zero)
{
DeleteProcThreadAttributeList(StartupInfo.lpAttributeList);
Marshal.FreeHGlobal(StartupInfo.lpAttributeList);
}
// Close process and thread handles
if (ProcessInfo.hProcess != IntPtr.Zero)
{
CloseHandle(ProcessInfo.hProcess);
}
if (ProcessInfo.hThread != IntPtr.Zero)
{
CloseHandle(ProcessInfo.hThread);
}
disposedValue = true;
}
}
~Process()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(false);
}
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// use the following line if the finalizer is overridden above.
GC.SuppressFinalize(this);
}
#endregion
}
}

View file

@ -0,0 +1,98 @@
using System;
using System.Runtime.InteropServices;
using static MiniTerm.Native.ProcessApi;
namespace MiniTerm
{
/// <summary>
/// Support for starting and configuring processes.
/// </summary>
/// <remarks>
/// Possible to replace with managed code? The key is being able to provide the PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE attribute
/// </remarks>
static class ProcessFactory
{
/// <summary>
/// Start and configure a process. The return value represents the process and should be disposed.
/// </summary>
internal static Process Start(string command, IntPtr attributes, IntPtr hPC)
{
var startupInfo = ConfigureProcessThread(hPC, attributes);
var processInfo = RunProcess(ref startupInfo, "cmd.exe");
return new Process(startupInfo, processInfo);
}
private static STARTUPINFOEX ConfigureProcessThread(IntPtr hPC, IntPtr attributes)
{
// this method implements the behavior described in https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session#preparing-for-creation-of-the-child-process
var lpSize = IntPtr.Zero;
var success = InitializeProcThreadAttributeList(
lpAttributeList: IntPtr.Zero,
dwAttributeCount: 1,
dwFlags: 0,
lpSize: ref lpSize
);
if (success || lpSize == IntPtr.Zero) // we're not expecting `success` here, we just want to get the calculated lpSize
{
throw new InvalidOperationException("Could not calculate the number of bytes for the attribute list. " + Marshal.GetLastWin32Error());
}
var startupInfo = new STARTUPINFOEX();
startupInfo.StartupInfo.cb = Marshal.SizeOf<STARTUPINFOEX>();
startupInfo.lpAttributeList = Marshal.AllocHGlobal(lpSize);
success = InitializeProcThreadAttributeList(
lpAttributeList: startupInfo.lpAttributeList,
dwAttributeCount: 1,
dwFlags: 0,
lpSize: ref lpSize
);
if (!success)
{
throw new InvalidOperationException("Could not set up attribute list. " + Marshal.GetLastWin32Error());
}
success = UpdateProcThreadAttribute(
lpAttributeList: startupInfo.lpAttributeList,
dwFlags: 0,
attribute: attributes,
lpValue: hPC,
cbSize: (IntPtr)IntPtr.Size,
lpPreviousValue: IntPtr.Zero,
lpReturnSize: IntPtr.Zero
);
if (!success)
{
throw new InvalidOperationException("Could not set pseudoconsole thread attribute. " + Marshal.GetLastWin32Error());
}
return startupInfo;
}
private static PROCESS_INFORMATION RunProcess(ref STARTUPINFOEX sInfoEx, string commandLine)
{
int securityAttributeSize = Marshal.SizeOf<SECURITY_ATTRIBUTES>();
var pSec = new SECURITY_ATTRIBUTES { nLength = securityAttributeSize };
var tSec = new SECURITY_ATTRIBUTES { nLength = securityAttributeSize };
var success = CreateProcess(
lpApplicationName: null,
lpCommandLine: commandLine,
lpProcessAttributes: ref pSec,
lpThreadAttributes: ref tSec,
bInheritHandles: false,
dwCreationFlags: EXTENDED_STARTUPINFO_PRESENT,
lpEnvironment: IntPtr.Zero,
lpCurrentDirectory: null,
lpStartupInfo: ref sInfoEx,
lpProcessInformation: out PROCESS_INFORMATION pInfo
);
if (!success)
{
throw new InvalidOperationException("Could not create process. " + Marshal.GetLastWin32Error());
}
return pInfo;
}
}
}

View file

@ -0,0 +1,35 @@
using System;
namespace MiniTerm
{
/// <summary>
/// C# version of:
/// https://blogs.msdn.microsoft.com/commandline/2018/08/02/windows-command-line-introducing-the-windows-pseudo-console-conpty/
/// https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session
///
/// System Requirements:
/// As of September 2018, requires Windows 10 with the "Windows Insider Program" installed for Redstone 5.
/// Also requires the Windows Insider Preview SDK: https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewSDK
/// </summary>
/// <remarks>
/// Basic design is:
/// Terminal UI starts the PseudoConsole, and controls it using a pair of PseudoConsolePipes
/// Terminal UI will run the Process (cmd.exe) and associate it with the PseudoConsole.
/// </remarks>
static class Program
{
static void Main(string[] args)
{
try
{
var terminal = new Terminal();
terminal.Run("cmd.exe");
}
catch (InvalidOperationException e)
{
Console.Error.WriteLine(e.Message);
throw;
}
}
}
}

View file

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MiniPty")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MiniPty")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("121d4818-bd57-433b-8ad5-c4e1ace7e7c0")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,39 @@
using Microsoft.Win32.SafeHandles;
using System;
using static MiniTerm.Native.PseudoConsoleApi;
namespace MiniTerm
{
/// <summary>
/// Utility functions around the new Pseudo Console APIs
/// </summary>
internal sealed class PseudoConsole : IDisposable
{
public static readonly IntPtr PseudoConsoleThreadAttribute = (IntPtr)PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE;
public IntPtr Handle { get; }
private PseudoConsole(IntPtr handle)
{
this.Handle = handle;
}
internal static PseudoConsole Create(SafeFileHandle inputReadSide, SafeFileHandle outputWriteSide, int width, int height)
{
var createResult = CreatePseudoConsole(
new COORD { X = (short)width, Y = (short)height },
inputReadSide, outputWriteSide,
0, out IntPtr hPC);
if(createResult != 0)
{
throw new InvalidOperationException("Could not create psuedo console. Error Code " + createResult);
}
return new PseudoConsole(hPC);
}
public void Dispose()
{
ClosePseudoConsole(Handle);
}
}
}

View file

@ -0,0 +1,46 @@
using Microsoft.Win32.SafeHandles;
using System;
using static MiniTerm.Native.PseudoConsoleApi;
namespace MiniTerm
{
/// <summary>
/// A pipe used to talk to the pseudoconsole, as described in:
/// https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session
/// </summary>
/// <remarks>
/// We'll have two instances of this class, one for input and one for output.
/// </remarks>
internal sealed class PseudoConsolePipe : IDisposable
{
public readonly SafeFileHandle ReadSide;
public readonly SafeFileHandle WriteSide;
public PseudoConsolePipe()
{
if (!CreatePipe(out ReadSide, out WriteSide, IntPtr.Zero, 0))
{
throw new InvalidOperationException("failed to create pipe");
}
}
#region IDisposable
void Dispose(bool disposing)
{
if (disposing)
{
ReadSide?.Dispose();
WriteSide?.Dispose();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}

View file

@ -0,0 +1,145 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static MiniTerm.Native.ConsoleApi;
namespace MiniTerm
{
/// <summary>
/// The UI of the terminal. It's just a normal console window, but we're managing the input/output.
/// In a "real" project this could be some other UI.
/// </summary>
internal sealed class Terminal
{
private const string ExitCommand = "exit\r";
private const string CtrlC_Command = "\x3";
public Terminal()
{
EnableVirtualTerminalSequenceProcessing();
}
/// <summary>
/// Newer versions of the windows console support interpreting virtual terminal sequences, we just have to opt-in
/// </summary>
private static void EnableVirtualTerminalSequenceProcessing()
{
var hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (!GetConsoleMode(hStdOut, out uint outConsoleMode))
{
throw new InvalidOperationException("Could not get console mode");
}
outConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
if (!SetConsoleMode(hStdOut, outConsoleMode))
{
throw new InvalidOperationException("Could not enable virtual terminal processing");
}
}
/// <summary>
/// Start the psuedoconsole and run the process as shown in
/// https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session#creating-the-pseudoconsole
/// </summary>
/// <param name="command">the command to run, e.g. cmd.exe</param>
public void Run(string command)
{
using (var inputPipe = new PseudoConsolePipe())
using (var outputPipe = new PseudoConsolePipe())
using (var pseudoConsole = PseudoConsole.Create(inputPipe.ReadSide, outputPipe.WriteSide, (short)Console.WindowWidth, (short)Console.WindowHeight))
using (var process = ProcessFactory.Start(command, PseudoConsole.PseudoConsoleThreadAttribute, pseudoConsole.Handle))
{
// copy all pseudoconsole output to stdout
Task.Run(() => CopyPipeToOutput(outputPipe.ReadSide));
// prompt for stdin input and send the result to the pseudoconsole
Task.Run(() => CopyInputToPipe(inputPipe.WriteSide));
// free resources in case the console is ungracefully closed (e.g. by the 'x' in the window titlebar)
OnClose(() => DisposeResources(process, pseudoConsole, outputPipe, inputPipe));
WaitForExit(process).WaitOne(Timeout.Infinite);
}
}
/// <summary>
/// Reads terminal input and copies it to the PseudoConsole
/// </summary>
/// <param name="inputWriteSide">the "write" side of the pseudo console input pipe</param>
private static void CopyInputToPipe(SafeFileHandle inputWriteSide)
{
using (var writer = new StreamWriter(new FileStream(inputWriteSide, FileAccess.Write)))
{
ForwardCtrlC(writer);
writer.AutoFlush = true;
writer.WriteLine(@"cd \");
while (true)
{
// send input character-by-character to the pipe
char key = Console.ReadKey(intercept: true).KeyChar;
writer.Write(key);
}
}
}
/// <summary>
/// Don't let ctrl-c kill the terminal, it should be sent to the process in the terminal.
/// </summary>
private static void ForwardCtrlC(StreamWriter writer)
{
Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true;
writer.Write(CtrlC_Command);
};
}
/// <summary>
/// Reads PseudoConsole output and copies it to the terminal's standard out.
/// </summary>
/// <param name="outputReadSide">the "read" side of the pseudo console output pipe</param>
private static void CopyPipeToOutput(SafeFileHandle outputReadSide)
{
using (var terminalOutput = Console.OpenStandardOutput())
using (var pseudoConsoleOutput = new FileStream(outputReadSide, FileAccess.Read))
{
pseudoConsoleOutput.CopyTo(terminalOutput);
}
}
/// <summary>
/// Get an AutoResetEvent that signals when the process exits
/// </summary>
private static AutoResetEvent WaitForExit(Process process) =>
new AutoResetEvent(false)
{
SafeWaitHandle = new SafeWaitHandle(process.ProcessInfo.hProcess, ownsHandle: false)
};
/// <summary>
/// Set a callback for when the terminal is closed (e.g. via the "X" window decoration button).
/// Intended for resource cleanup logic.
/// </summary>
private static void OnClose(Action handler)
{
SetConsoleCtrlHandler(eventType =>
{
if(eventType == CtrlTypes.CTRL_CLOSE_EVENT)
{
handler();
}
return false;
}, true);
}
private void DisposeResources(params IDisposable[] disposables)
{
foreach (var disposable in disposables)
{
disposable.Dispose();
}
}
}
}

View file

@ -0,0 +1,19 @@
# MiniTerm
Experimental terminal using the new PTY APIs from Microsoft. Written in C#, and heavily based on the native code examples.
## Status
Demonstrates the basic API calls required, but not intended for "real-world" usage.
## Resources
- [Introductory blog post from Microsoft](https://blogs.msdn.microsoft.com/commandline/2018/08/02/windows-command-line-introducing-the-windows-pseudo-console-conpty/)
- [MSDN Documentation](https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session)
## System Requirements
See the Introductory blog post from Microsoft for the full setup instructions. This project has been tested with:
- OS: Windows 10 Pro Build 17744
- SDK: Windows_InsiderPreview_SDK_en-us_17749

View file

@ -0,0 +1,58 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Samples.Terminal
{
/// <summary>
/// Implements a bounded queue that won't block on overflow; instead the oldest item is discarded.
/// </summary>
/// <typeparam name="T"></typeparam>
public class ConcurrentBoundedQueue<T> : ConcurrentQueue<T>
{
public ConcurrentBoundedQueue(int capacity)
{
Capacity = GetAlignedCapacity(capacity);
}
public ConcurrentBoundedQueue(IEnumerable<T> collection, int capacity) : base(collection)
{
Capacity = GetAlignedCapacity(capacity);
}
private int GetAlignedCapacity(int n)
{
if (n < 2)
{
throw new ArgumentException("Capacity must be at least 2");
}
var f = Math.Log(n, 2);
var p = Math.Ceiling(f);
return (int) Math.Pow(2, p);
}
public new void Enqueue(T item)
{
// if we're about to overflow, dump oldest item
if (Count >= Capacity)
{
lock (this)
{
while (Count >= Capacity)
{
TryDequeue(out _);
}
}
}
base.Enqueue(item);
}
public int Capacity
{
get; private set;
}
}
}

View file

@ -0,0 +1,31 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Samples.Terminal
{
internal static class NativeMethods
{
private static int MakeHRFromErrorCode(int errorCode)
{
// Don't convert it if it is already an HRESULT
if ((0xFFFF0000 & errorCode) != 0)
{
Debug.Assert(false, "errorCode is already HRESULT");
return errorCode;
}
return unchecked(((int)0x80070000) | errorCode);
}
internal static Exception GetExceptionForWin32Error(int errorCode)
{
return Marshal.GetExceptionForHR(MakeHRFromErrorCode(errorCode));
}
internal static Exception GetExceptionForLastWin32Error()
{
return GetExceptionForWin32Error(Marshal.GetLastWin32Error());
}
}
}

View file

@ -0,0 +1,147 @@
/*
* This is a demo that shows how we can have a stream-oriented view of characters from the console
* while also listening to console events like mouse, menu, focus, buffer/viewport(1) resize events.
*
* This has always been tricky to do because ReadConsoleW/A doesn't allow retrieving events.
* Only ReadConsoleInputW/A returns events, but isn't stream-oriented. Using both doesn't work because
* ReadConsoleW/A flushes the input queue, meaning calls to ReadConsoleInputW/A will wait forever.
*
* I do this by deriving a new Stream class which wraps ReadConsoleInputW and accepts a provider/consumer
* implementation of BlockingCollection<Kernel32.INPUT_RECORD>. This allows asynchronous monitoring of
* console events while simultaneously streaming the character input. I also use Mark Gravell's great
* System.IO.Pipelines utility classes (2) and David Hall's excellent P/Invoke wrappers (3) to make this
* demo cleaner to read; both are pulled from NuGet.
*
* (1) in versions of windows 10 prior to 1809, the buffer resize event only fires for enlarging
* the viewport, as this would cause the buffer to be enlarged too. Now it fires even when
* shrinking the viewport, which won't change the buffer size.
*
* (2) https://github.com/mgravell/Pipelines.Sockets.Unofficial
* https://www.nuget.org/packages/Pipelines.Sockets.Unofficial
*
* (3) https://github.com/dahall/Vanara
* https://www.nuget.org/packages/Vanara.Pinvoke.Kernel32
*
* Oisin Grehan - 2019/4/21
*
* https://twitter.com/oising
* https://github.com/oising
*/
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Pipelines.Sockets.Unofficial;
using Vanara.PInvoke;
namespace Samples.Terminal
{
internal class Program
{
private static async Task Main(string[] args)
{
// run for 90 seconds
var timeout = TimeSpan.FromSeconds(90);
// in reality this will likely never be reached, but it is useful to guard against
// conditions where the queue isn't drained, or not drained fast enough.
const int maxNonKeyEventRetention = 128;
var source = new CancellationTokenSource(timeout);
var token = source.Token;
var handle = Kernel32.GetStdHandle(Kernel32.StdHandleType.STD_INPUT_HANDLE);
if (!Kernel32.GetConsoleMode(handle, out Kernel32.CONSOLE_INPUT_MODE mode))
throw NativeMethods.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
mode |= Kernel32.CONSOLE_INPUT_MODE.ENABLE_WINDOW_INPUT;
mode |= Kernel32.CONSOLE_INPUT_MODE.ENABLE_VIRTUAL_TERMINAL_INPUT;
mode &= ~Kernel32.CONSOLE_INPUT_MODE.ENABLE_ECHO_INPUT;
mode &= ~Kernel32.CONSOLE_INPUT_MODE.ENABLE_LINE_INPUT;
if (!Kernel32.SetConsoleMode(handle, mode))
throw NativeMethods.GetExceptionForLastWin32Error();
// base our provider/consumer on a bounded queue to keep memory usage under control
var events = new BlockingCollection<Kernel32.INPUT_RECORD>(
new ConcurrentBoundedQueue<Kernel32.INPUT_RECORD>(maxNonKeyEventRetention));
// Task that will consume non-key events asynchronously
var consumeEvents = Task.Run(() =>
{
Console.WriteLine("consumeEvents started");
try
{
while (!events.IsCompleted)
{
// blocking call
var record = events.Take(token);
Console.WriteLine("record: {0}",
Enum.GetName(typeof(Kernel32.EVENT_TYPE), record.EventType));
}
}
catch (OperationCanceledException)
{
// timeout
}
Console.WriteLine("consumeEvents ended");
}, token);
// Task that will watch for key events while feeding non-key events into our provider/consumer collection
var readInputAndProduceEvents = Task.Run(async () =>
{
//So, this is the key point - we cannot use the following or we lose all non-key events:
// Stream stdin = Console.OpenStandardInput();
// get a unicode character stream over console input
Stream stdin = new ReadConsoleInputStream(handle, events);
// wrap in a System.IO.Pipelines.PipeReader to get clean async and span/memory usage
var reader = StreamConnection.GetReader(stdin);
while (!token.IsCancellationRequested)
{
// blocking call
var result = await reader.ReadAsync(token);
if (result.IsCanceled)
break;
var sequence = result.Buffer;
var segment = sequence.Start;
while (sequence.TryGet(ref segment, out var mem))
{
// decode back from unicode
var datum = Encoding.Unicode.GetString(mem.Span);
Console.Write(datum);
}
reader.AdvanceTo(sequence.End);
}
}, token);
Console.WriteLine("Running");
try
{
await Task.WhenAll(consumeEvents, readInputAndProduceEvents);
}
catch (OperationCanceledException)
{
// timeout
}
Console.WriteLine("press any key...");
Console.ReadKey(true);
}
}
}

View file

@ -0,0 +1,16 @@
# ReadConsoleInputStream Demo
This is a demo that shows how we can have a stream-oriented view of characters from the console while also listening to console events like mouse, menu, focus, buffer/viewport resize events. This is partcularly useful when working with VT100 streams and ConPTY.
This has always been tricky to do because ReadConsoleW/A doesn't allow retrieving events. Only ReadConsoleInputW/A returns events, but isn't stream-oriented. Using both doesn't work because ReadConsoleW/A flushes the input queue, meaning calls to ReadConsoleInputW/A will wait forever.
I do this by deriving a new Stream class which wraps ReadConsoleInputW and accepts a provider/consumer implementation of BlockingCollection<Kernel32.INPUT_RECORD>. This allows asynchronous monitoring of console events while simultaneously streaming the character input. I also use Mark Gravell's great System.IO.Pipelines utility classes and David Hall's excellent P/Invoke wrappers to make this demo cleaner to read; both are pulled from NuGet.
**Note:**
In versions of windows 10 prior to 1809, the buffer resize event only fires for enlarging the viewport, as this would cause the buffer to be enlarged too. Now it fires even when shrinking the viewport, which won't change the buffer size.
NuGet packages used (GitHub links):
* [Pipelines.Sockets.Unofficial](https://github.com/mgravell/Pipelines.Sockets.Unofficial)
* [Vanara P/Invoke](https://github.com/dahall/Vanara)

View file

@ -0,0 +1,198 @@
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using Vanara.PInvoke;
namespace Samples.Terminal
{
/// <summary>
/// Provides a Stream-oriented view over the console's input buffer key events
/// while also collecting out of band events like buffer resize, menu etc in
/// a caller-provided BlockingCollection.
/// </summary>
/// <remarks>The buffer contains unicode chars, not 8 bit CP encoded chars as we rely on ReadConsoleInputW.</remarks>
public sealed class ReadConsoleInputStream : Stream
{
private const int BufferSize = 256;
private const int BytesPerWChar = 2;
private readonly BlockingCollection<Kernel32.INPUT_RECORD> _nonKeyEvents;
private IntPtr _handle;
/// <summary>
/// Creates an instance of ReadConsoleInputStream over the standard handle for StdIn.
/// </summary>
/// <param name="nonKeyEvents">A BlockingCollection provider/consumer collection for collecting non key events.</param>
public ReadConsoleInputStream(BlockingCollection<Kernel32.INPUT_RECORD> nonKeyEvents) :
this(Kernel32.GetStdHandle(Kernel32.StdHandleType.STD_INPUT_HANDLE), nonKeyEvents)
{
}
/// <summary>
/// Creates an instance of ReadConsoleInputStream over a caller-provided standard handle for stdin.
/// </summary>
/// <param name="handle">A HFILE handle representing StdIn</param>
/// <param name="nonKeyEvents">A BlockingCollection provider/consumer collection for collecting non key events.</param>
internal ReadConsoleInputStream(HFILE handle,
BlockingCollection<Kernel32.INPUT_RECORD> nonKeyEvents)
{
Debug.Assert(handle.IsInvalid == false, "handle.IsInvalid == false");
_handle = handle.DangerousGetHandle();
_nonKeyEvents = nonKeyEvents;
}
public override bool CanRead { get; } = true;
public override bool CanWrite => false;
public override bool CanSeek => false;
public override long Length => throw new NotSupportedException("Seek not supported.");
public override long Position
{
get => throw new NotSupportedException("Seek not supported.");
set => throw new NotSupportedException("Seek not supported.");
}
protected override void Dispose(bool disposing)
{
_handle = IntPtr.Zero;
base.Dispose(disposing);
}
public override int Read(byte[] buffer, int offset, int count)
{
ValidateRead(buffer, offset, count);
Debug.Assert(offset >= 0, "offset >= 0");
Debug.Assert(count >= 0, "count >= 0");
Debug.Assert(buffer != null, "bytes != null");
// Don't corrupt memory when multiple threads are erroneously writing
// to this stream simultaneously.
if (buffer.Length - offset < count)
throw new IndexOutOfRangeException("IndexOutOfRange_IORaceCondition");
int bytesRead;
int ret;
if (buffer.Length == 0)
{
bytesRead = 0;
ret = Win32Error.ERROR_SUCCESS;
}
else
{
var charsRead = 0;
bytesRead = 0;
var records = new Kernel32.INPUT_RECORD[BufferSize];
// begin input loop
do
{
var readSuccess = Kernel32.ReadConsoleInput(_handle, records, BufferSize, out var recordsRead);
Debug.WriteLine("Read {0} input record(s)", recordsRead);
// some of the arithmetic here is deliberately more explicit than it needs to be
// in order to show how 16-bit unicode WCHARs are packed into the buffer. The console
// subsystem is one of the last bastions of UCS-2, so until UTF-16 is fully adopted
// the two-byte character assumptions below will hold.
if (readSuccess && recordsRead > 0)
{
for (var index = 0; index < recordsRead; index++)
{
var record = records[index];
if (record.EventType == Kernel32.EVENT_TYPE.KEY_EVENT)
{
// skip key up events - if not, every key will be duped in the stream
if (record.Event.KeyEvent.bKeyDown == false) continue;
// pack ucs-2/utf-16le/unicode chars into position in our byte[] buffer.
var glyph = (ushort) record.Event.KeyEvent.uChar;
var lsb = (byte) (glyph & 0xFFu);
var msb = (byte) ((glyph >> 8) & 0xFFu);
// ensure we accommodate key repeat counts
for (var n = 0; n < record.Event.KeyEvent.wRepeatCount; n++)
{
buffer[offset + charsRead * BytesPerWChar] = lsb;
buffer[offset + charsRead * BytesPerWChar + 1] = msb;
charsRead++;
}
}
else
{
// ignore focus events; not doing so makes debugging absolutely hilarious
// when breakpoints repeatedly cause focus events to occur as your view toggles
// between IDE and console.
if (record.EventType != Kernel32.EVENT_TYPE.FOCUS_EVENT)
{
// I assume success adding records - this is not so critical
// if it is critical to you, loop on this with a miniscule delay
_nonKeyEvents.TryAdd(record);
}
}
}
bytesRead = charsRead * BytesPerWChar;
}
else
{
Debug.Assert(bytesRead == 0, "bytesRead == 0");
}
} while (bytesRead == 0);
Debug.WriteLine("Read {0} character(s)", charsRead);
ret = Win32Error.ERROR_SUCCESS;
}
var errCode = ret;
if (Win32Error.ERROR_SUCCESS != errCode)
throw NativeMethods.GetExceptionForWin32Error(errCode);
return bytesRead;
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException("Write operations not implemented.");
}
public override void Flush()
{
throw new NotSupportedException("Flush/Write not supported.");
}
public override void SetLength(long value)
{
throw new NotSupportedException("Seek not supported.");
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("Seek not supported.");
}
private void ValidateRead(byte[] buffer, int offset, int count)
{
if (buffer == null)
throw new ArgumentNullException(nameof(buffer));
if (offset < 0 || count < 0)
throw new ArgumentOutOfRangeException(offset < 0 ? nameof(offset) : nameof(count),
"offset or count cannot be negative numbers.");
if (buffer.Length - offset < count)
throw new ArgumentException("invalid offset length.");
if (!CanRead) throw new NotSupportedException("Get read not supported.");
}
}
}

View file

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<LangVersion>latest</LangVersion>
<RootNamespace>Samples.Terminal</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Pipelines.Sockets.Unofficial" Version="2.0.22" />
<PackageReference Include="Vanara.PInvoke.Kernel32" Version="2.3.6" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.156
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadConsoleInputStreamDemo", "ReadConsoleInputStreamDemo.csproj", "{62F500DE-4F06-4B46-B7AF-02AF21296F00}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{62F500DE-4F06-4B46-B7AF-02AF21296F00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62F500DE-4F06-4B46-B7AF-02AF21296F00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62F500DE-4F06-4B46-B7AF-02AF21296F00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62F500DE-4F06-4B46-B7AF-02AF21296F00}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55A9793B-D717-4A6E-A8FE-ABC6CD3B17BA}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorTool", "ColorTool\ColorTool.csproj", "{97F4550F-5775-4E40-8ECF-A03479884120}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{97F4550F-5775-4E40-8ECF-A03479884120}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97F4550F-5775-4E40-8ECF-A03479884120}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97F4550F-5775-4E40-8ECF-A03479884120}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97F4550F-5775-4E40-8ECF-A03479884120}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
</startup>
</configuration>

View file

@ -0,0 +1,134 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using System;
using System.Drawing;
using System.Linq;
namespace ColorTool
{
/// <summary>
/// Represents a colorscheme that can be applied to a console.
/// </summary>
public class ColorScheme
{
public ColorScheme(uint[] colorTable, ConsoleAttributes consoleAttributes)
{
ColorTable = colorTable;
ConsoleAttributes = consoleAttributes;
}
public uint[] ColorTable { get; }
public ConsoleAttributes ConsoleAttributes { get; }
public ushort? ScreenColorAttributes =>
CalculateBackgroundForegroundAttributes(
this.ConsoleAttributes.Background,
this.ConsoleAttributes.Foreground
);
public ushort? PopupColorAttributes =>
CalculateBackgroundForegroundAttributes(
this.ConsoleAttributes.PopupBackground,
this.ConsoleAttributes.PopupForeground
);
public Color this[int index] => UIntToColor(ColorTable[index]);
private static Color UIntToColor(uint color)
{
byte r = (byte)(color >> 0);
byte g = (byte)(color >> 8);
byte b = (byte)(color >> 16);
return Color.FromArgb(r, g, b);
}
private ushort? CalculateBackgroundForegroundAttributes(uint? background, uint? foreground)
{
if(!(background.HasValue && foreground.HasValue))
{
return null;
}
int fgidx = this.CalculateIndex(foreground.Value);
int bgidx = this.CalculateIndex(background.Value);
var attributes = (ushort)(fgidx | (bgidx << 4));
return attributes;
}
public int CalculateIndex(uint value) =>
ColorTable.Select((color, idx) => Tuple.Create(color, idx))
.OrderBy(Difference(value))
.First().Item2;
private static Func<Tuple<uint, int>, double> Difference(uint c1) =>
// heuristic 1: nearest neighbor in RGB space
// tup => Distance(RGB(c1), RGB(tup.Item1));
// heuristic 2: nearest neighbor in RGB space
// tup => Distance(HSV(c1), HSV(tup.Item1));
// heuristic 3: weighted RGB L2 distance
tup => WeightedRGBSimilarity(c1, tup.Item1);
private static double WeightedRGBSimilarity(uint c1, uint c2)
{
var rgb1 = RGB(c1);
var rgb2 = RGB(c2);
var dist = rgb1.Zip(rgb2, (a, b) => Math.Pow((int)a - (int)b, 2)).ToArray();
var rbar = (rgb1[0] + rgb1[0]) / 2.0;
return Math.Sqrt(dist[0] * (2 + rbar / 256.0) + dist[1] * 4 + dist[2] * (2 + (255 - rbar) / 256.0));
}
internal static uint[] RGB(uint c) => new[] { c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF };
internal static uint[] HSV(uint c)
{
var rgb = RGB(c).Select(_ => (int)_).ToArray();
int max = rgb.Max();
int min = rgb.Min();
int d = max - min;
int h = 0;
int s = (int)(255 * ((max == 0) ? 0 : d / (double)max));
int v = max;
if (d != 0)
{
double dh;
if (rgb[0] == max) dh = ((rgb[1] - rgb[2]) / (double)d);
else if (rgb[1] == max) dh = 2.0 + ((rgb[2] - rgb[0]) / (double)d);
else /* if (rgb[2] == max) */ dh = 4.0 + ((rgb[0] - rgb[1]) / (double)d);
dh *= 60;
if (dh < 0) dh += 360.0;
h = (int)(dh * 255.0 / 360.0);
}
return new[] { (uint)h, (uint)s, (uint)v };
}
internal void Dump()
{
Action<string, uint> _dump = (str, c) =>
{
var rgb = RGB(c);
var hsv = HSV(c);
Console.WriteLine($"{str} =\tRGB({rgb[0]}, {rgb[1]}, {rgb[2]}),\tHSV({hsv[0]}, {hsv[1]}, {hsv[2]})");
};
for (int i = 0; i < 16; ++i)
{
_dump($"Color[{i}]", ColorTable[i]);
}
if (ConsoleAttributes.Foreground != null)
{
_dump("FG ", ConsoleAttributes.Foreground.Value);
}
if (ConsoleAttributes.Background != null)
{
_dump("BG ", ConsoleAttributes.Background.Value);
}
}
}
}

View file

@ -0,0 +1,205 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using System;
using System.Collections.Generic;
namespace ColorTool
{
/// <summary>
/// Displays the color table that demonstrates the current colorscheme.
/// </summary>
static class ColorTable
{
private const int DarkBlack = 0;
private const int DarkBlue = 1;
private const int DarkGreen = 2;
private const int DarkCyan = 3;
private const int DarkRed = 4;
private const int DarkMagenta = 5;
private const int DarkYellow = 6;
private const int DarkWhite = 7;
private const int BrightBlack = 8;
private const int BrightBlue = 9;
private const int BrightGreen = 10;
private const int BrightCyan = 11;
private const int BrightRed = 12;
private const int BrightMagenta = 13;
private const int BrightYellow = 14;
private const int BrightWhite = 15;
// This is the order of colors when output by the table.
private static readonly IReadOnlyList<int> Foregrounds = new[]
{
BrightWhite,
DarkBlack,
BrightBlack,
DarkRed,
BrightRed,
DarkGreen,
BrightGreen,
DarkYellow,
BrightYellow,
DarkBlue,
BrightBlue,
DarkMagenta,
BrightMagenta,
DarkCyan,
BrightCyan,
DarkWhite,
BrightWhite
};
private static readonly IReadOnlyList<int> Backgrounds = new[]
{
DarkBlack,
DarkRed,
DarkGreen,
DarkYellow,
DarkBlue,
DarkMagenta,
DarkCyan,
DarkWhite
};
private const string TestText = " gYw ";
private static readonly IReadOnlyList<string> AnsiForegroundSequences = new[]
{
"m",
"1m",
"30m",
"1;30m",
"31m",
"1;31m",
"32m",
"1;32m",
"33m",
"1;33m",
"34m",
"1;34m",
"35m",
"1;35m",
"36m",
"1;36m",
"37m",
"1;37m"
};
private static readonly IReadOnlyList<string> AnsiBackgroundSequences = new[]
{
"m",
"40m",
"41m",
"42m",
"43m",
"44m",
"45m",
"46m",
"47m"
};
public static void PrintTable()
{
ConsoleColor[] colors = (ConsoleColor[])ConsoleColor.GetValues(typeof(ConsoleColor));
// Save the current background and foreground colors.
ConsoleColor currentBackground = Console.BackgroundColor;
ConsoleColor currentForeground = Console.ForegroundColor;
Console.Write("\t");
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
{
if (bg > 0) Console.Write(" ");
Console.Write(" ");
Console.Write(bg == 0 ? " " : AnsiBackgroundSequences[bg]);
Console.Write(" ");
}
Console.WriteLine();
for (int fg = 0; fg < AnsiForegroundSequences.Count; fg++)
{
Console.ForegroundColor = currentForeground;
Console.BackgroundColor = currentBackground;
if (fg >= 0) Console.Write(AnsiForegroundSequences[fg] + "\t");
if (fg == 0) Console.ForegroundColor = currentForeground;
else Console.ForegroundColor = colors[Foregrounds[fg - 1]];
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
{
if (bg > 0) Console.Write(" ");
if (bg == 0)
Console.BackgroundColor = currentBackground;
else Console.BackgroundColor = colors[Backgrounds[bg - 1]];
Console.Write(TestText);
Console.BackgroundColor = currentBackground;
}
Console.Write("\n");
}
Console.Write("\n");
// Reset foreground and background colors
Console.ForegroundColor = currentForeground;
Console.BackgroundColor = currentBackground;
}
public static void PrintTableWithVt()
{
Console.Write("\t");
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
{
if (bg > 0) Console.Write(" ");
Console.Write(" ");
Console.Write(bg == 0 ? " " : AnsiBackgroundSequences[bg]);
Console.Write(" ");
}
Console.WriteLine();
for (int fg = 0; fg < AnsiForegroundSequences.Count; fg++)
{
Console.Write("\x1b[m");
if (fg >= 0)
{
Console.Write(AnsiForegroundSequences[fg] + "\t");
}
if (fg == 0)
{
Console.Write("\x1b[39m");
}
else
{
Console.Write("\x1b[" + AnsiForegroundSequences[fg]);
}
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
{
if (bg > 0)
{
Console.Write(" ");
}
if (bg == 0)
{
Console.Write("\x1b[49m");
}
else
{
Console.Write("\x1b[" + AnsiBackgroundSequences[bg]);
}
Console.Write(TestText);
Console.Write("\x1b[49m");
}
Console.Write("\n");
}
Console.Write("\n");
// Reset foreground and background colors
Console.Write("\x1b[m");
}
}
}

View file

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,94 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using System;
using System.Runtime.InteropServices;
namespace ColorTool
{
static class ConsoleAPI
{
private const int StdOutputHandle = -11;
public const int ColorTableSize = 16;
[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
public short X;
public short Y;
}
public struct SMALL_RECT
{
public short Left;
public short Top;
public short Right;
public short Bottom;
}
[Flags]
public enum ConsoleOutputModes : uint
{
ENABLE_PROCESSED_OUTPUT = 0x0001,
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002,
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004,
DISABLE_NEWLINE_AUTO_RETURN = 0x0008,
ENABLE_LVB_GRID_WORLDWIDE = 0x0010,
}
[StructLayout(LayoutKind.Sequential)]
public struct CONSOLE_SCREEN_BUFFER_INFO_EX
{
public uint cbSize;
public COORD dwSize;
public COORD dwCursorPosition;
public ushort wAttributes;
public SMALL_RECT srWindow;
public COORD dwMaximumWindowSize;
public ushort wPopupAttributes;
public bool bFullscreenSupported;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public uint[] ColorTable;
public static CONSOLE_SCREEN_BUFFER_INFO_EX Create()
{
return new CONSOLE_SCREEN_BUFFER_INFO_EX { cbSize = 96 };
}
}
public static IntPtr GetStdOutputHandle() => GetStdHandle(StdOutputHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetConsoleScreenBufferInfoEx(IntPtr hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFO_EX ConsoleScreenBufferInfo);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetConsoleScreenBufferInfoEx(IntPtr ConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFO_EX ConsoleScreenBufferInfoEx);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteConsole(
IntPtr hConsoleOutput,
string lpBuffer,
uint nNumberOfCharsToWrite,
out uint lpNumberOfCharsWritten,
IntPtr lpReserved
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
public static uint RGB(int r, int g, int b)
{
return (uint)r + (((uint)g) << 8) + (((uint)b) << 16);
}
}
}

View file

@ -0,0 +1,26 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
namespace ColorTool
{
/// <summary>
/// Keeps track of the color table indices for the background/foreground in a colorscheme.
/// </summary>
public readonly struct ConsoleAttributes
{
public ConsoleAttributes(uint? background, uint? foreground, uint? popupBackground, uint? popupForeground)
{
Background = background;
Foreground = foreground;
PopupBackground = popupBackground;
PopupForeground = popupForeground;
}
public uint? Foreground { get; }
public uint? Background { get; }
public uint? PopupForeground { get; }
public uint? PopupBackground { get; }
}
}

View file

@ -0,0 +1,47 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using System;
using static ColorTool.ConsoleAPI;
namespace ColorTool.ConsoleTargets
{
/// <summary>
/// A console target that writes to the currently open console.
/// </summary>
class CurrentConsoleTarget : IConsoleTarget
{
public void ApplyColorScheme(ColorScheme colorScheme, bool quietMode)
{
CONSOLE_SCREEN_BUFFER_INFO_EX csbiex = CONSOLE_SCREEN_BUFFER_INFO_EX.Create();
IntPtr hOut = GetStdOutputHandle();
bool success = GetConsoleScreenBufferInfoEx(hOut, ref csbiex);
if (!success)
{
throw new InvalidOperationException("Could not obtain console screen buffer");
}
csbiex.srWindow.Bottom++;
for (int i = 0; i < 16; i++)
{
csbiex.ColorTable[i] = colorScheme.ColorTable[i];
}
if(colorScheme.ScreenColorAttributes is ushort wAttrs)
{
csbiex.wAttributes = wAttrs;
}
if(colorScheme.PopupColorAttributes is ushort wPopupAttrs)
{
csbiex.wPopupAttributes = wPopupAttrs;
}
SetConsoleScreenBufferInfoEx(hOut, ref csbiex);
if (!quietMode)
{
ColorTable.PrintTable();
}
}
}
}

View file

@ -0,0 +1,36 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using Microsoft.Win32;
using System;
namespace ColorTool.ConsoleTargets
{
/// <summary>
/// A console target that writes to the Windows registry to modify system defaults
/// </summary>
class DefaultConsoleTarget : IConsoleTarget
{
public void ApplyColorScheme(ColorScheme colorScheme, bool quietMode)
{
RegistryKey consoleKey = Registry.CurrentUser.OpenSubKey("Console", true);
for (int i = 0; i < colorScheme.ColorTable.Length; i++)
{
string valueName = "ColorTable" + (i < 10 ? "0" : "") + i;
consoleKey.SetValue(valueName, colorScheme.ColorTable[i], RegistryValueKind.DWord);
}
if(colorScheme.ScreenColorAttributes is ushort screenColors)
{
consoleKey.SetValue("ScreenColors", screenColors, RegistryValueKind.DWord);
}
if(colorScheme.PopupColorAttributes is ushort popupColors)
{
consoleKey.SetValue("PopupColors", popupColors, RegistryValueKind.DWord);
}
Console.WriteLine(Resources.WroteToDefaults);
}
}
}

View file

@ -0,0 +1,15 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
namespace ColorTool.ConsoleTargets
{
/// <summary>
/// A console that can have a color scheme applied to it.
/// </summary>
interface IConsoleTarget
{
void ApplyColorScheme(ColorScheme colorScheme, bool quietMode);
}
}

View file

@ -0,0 +1,69 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using System;
using System.Collections.Generic;
using System.Drawing;
using static ColorTool.ConsoleAPI;
namespace ColorTool.ConsoleTargets
{
/// <summary>
/// A console target that writes to the currently open console, using VT sequences.
/// </summary>
class VirtualTerminalConsoleTarget : IConsoleTarget
{
// Use a Console index in to get a VT index out.
public static readonly IReadOnlyList<int> VirtualTerminalIndices = new[]
{
0, // Dark Black
4, // Dark Blue
2, // Dark Green
6, // Dark Cyan
1, // Dark Red
5, // Dark Magenta
3, // Dark Yellow
7, // Dark White
8+0, // Bright Black
8+4, // Bright Blue
8+2, // Bright Green
8+6, // Bright Cyan
8+1, // Bright Red
8+5, // Bright Magenta
8+3, // Bright Yellow
8+7, // Bright White
};
public void ApplyColorScheme(ColorScheme colorScheme, bool quietMode)
{
IntPtr hOut = GetStdOutputHandle();
uint originalMode;
uint requestedMode;
bool succeeded = GetConsoleMode(hOut, out originalMode);
if (succeeded)
{
requestedMode = originalMode | (uint)ConsoleAPI.ConsoleOutputModes.ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, requestedMode);
}
for (int i = 0; i < colorScheme.ColorTable.Length; i++)
{
int vtIndex = VirtualTerminalIndices[i];
Color color = colorScheme[i];
string s = $"\x1b]4;{vtIndex};rgb:{color.R:X}/{color.G:X}/{color.B:X}\x7";
Console.Write(s);
}
if (!quietMode)
{
ColorTable.PrintTableWithVt();
}
if (succeeded)
{
SetConsoleMode(hOut, originalMode);
}
}
}
}

View file

@ -0,0 +1,150 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using ColorTool.ConsoleTargets;
using ColorTool.SchemeWriters;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ColorTool
{
static class Program
{
private static bool quietMode = false;
private static bool reportErrors = false;
private static bool setDefaults = false;
private static bool setProperties = true;
private static bool setUnixStyle = false;
public static void Main(string[] args)
{
if (args.Length < 1)
{
Usage();
return;
}
for (int i = 0; i < args.Length; i++)
{
string arg = args[i];
switch (arg)
{
case "-c":
case "--current":
ColorTable.PrintTable();
return;
case "-e":
case "--errors":
reportErrors = true;
break;
case "-q":
case "--quiet":
quietMode = true;
break;
case "-d":
case "--defaults":
setDefaults = true;
setProperties = false;
break;
case "-b":
case "--both":
setDefaults = true;
setProperties = true;
break;
case "-?":
case "--help":
Usage();
return;
case "-v":
case "--version":
Version();
return;
case "-l":
case "--location":
SchemeManager.PrintSchemesDirectory();
return;
case "-x":
case "--xterm":
setUnixStyle = true;
setProperties = true;
break;
case "-o":
case "--output":
if (i + 1 < args.Length)
{
new IniSchemeWriter().ExportCurrentAsIni(args[i + 1]);
}
else
{
OutputUsage();
}
return;
case "-s":
case "--schemes":
SchemeManager.PrintSchemes();
return;
default:
break;
}
}
string schemeName = args[args.Length - 1];
ColorScheme colorScheme = SchemeManager.GetScheme(schemeName, reportErrors);
if (colorScheme == null)
{
Console.WriteLine(string.Format(Resources.SchemeNotFound, schemeName));
return;
}
foreach (var target in GetConsoleTargets())
{
target.ApplyColorScheme(colorScheme, quietMode);
}
}
private static void Usage()
{
Console.WriteLine(Resources.Usage,
string.Join($"{Environment.NewLine} ", SchemeManager.GetParsers().Select(p => p.Name)));
}
private static void OutputUsage()
{
Console.WriteLine(Resources.OutputUsage);
}
private static void Version()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var info = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
Console.WriteLine($"colortool v{info.FileVersion}");
}
/// <summary>
/// Returns an enumerable of consoles that we want to apply the colorscheme to.
/// The contents of this enumerable depends on the user's provided command line flags.
/// </summary>
private static IEnumerable<IConsoleTarget> GetConsoleTargets()
{
if (setDefaults)
{
yield return new DefaultConsoleTarget();
}
if (setProperties)
{
if (setUnixStyle)
{
yield return new VirtualTerminalConsoleTarget();
}
else
{
yield return new CurrentConsoleTarget();
}
}
}
}
}

View file

@ -0,0 +1,7 @@
{
"profiles": {
"ColorTool": {
"commandName": "Project"
}
}
}

View file

@ -0,0 +1,143 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ColorTool {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ColorTool.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Error loading ini file &quot;{0}&quot;.
/// </summary>
public static string IniLoadError {
get {
return ResourceManager.GetString("IniLoadError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error loading ini file &quot;{0}&quot;
/// for key &quot;{1}&quot;
/// the value &quot;{2}&quot; is invalid.
/// </summary>
public static string IniParseError {
get {
return ResourceManager.GetString("IniParseError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid Color.
/// </summary>
public static string InvalidColor {
get {
return ResourceManager.GetString("InvalidColor", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid scheme - did not find 16 colors.
/// </summary>
public static string InvalidNumberOfColors {
get {
return ResourceManager.GetString("InvalidNumberOfColors", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Usage: colortool -o &lt;filename&gt;.
/// </summary>
public static string OutputUsage {
get {
return ResourceManager.GetString("OutputUsage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Could not find or load &quot;{0}&quot;.
/// </summary>
public static string SchemeNotFound {
get {
return ResourceManager.GetString("SchemeNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Usage:
/// colortool.exe [options] &lt;schemename&gt;
///ColorTool is a utility for helping to set the color palette of the Windows Console.
///By default, applies the colors in the specified .itermcolors or .ini file to the current console window.
///This does NOT save the properties automatically. For that, you&apos;ll need to open the properties sheet and hit &quot;Ok&quot;.
///Included should be a `schemes/` directory with a selection of schemes of both formats for examples.
///Feel free to add your own preferred scheme to that directory. [rest of string was truncated]&quot;;.
/// </summary>
public static string Usage {
get {
return ResourceManager.GetString("Usage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Wrote selected scheme to the defaults..
/// </summary>
public static string WroteToDefaults {
get {
return ResourceManager.GetString("WroteToDefaults", resourceCulture);
}
}
}
}

View file

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="IniLoadError" xml:space="preserve">
<value>Error loading ini file "{0}"</value>
</data>
<data name="IniParseError" xml:space="preserve">
<value>Error loading ini file "{0}"
for key "{1}"
the value "{2}" is invalid</value>
</data>
<data name="InvalidColor" xml:space="preserve">
<value>Invalid Color</value>
</data>
<data name="InvalidNumberOfColors" xml:space="preserve">
<value>Invalid scheme - did not find 16 colors</value>
</data>
<data name="OutputUsage" xml:space="preserve">
<value>Usage: colortool -o &lt;filename&gt;</value>
</data>
<data name="SchemeNotFound" xml:space="preserve">
<value>Could not find or load "{0}"</value>
</data>
<data name="Usage" xml:space="preserve">
<value>Usage:
colortool.exe [options] &lt;schemename&gt;
ColorTool is a utility for helping to set the color palette of the Windows Console.
By default, applies the colors in the specified .itermcolors, .json or .ini file to the current console window.
This does NOT save the properties automatically. For that, you'll need to open the properties sheet and hit "Ok".
Included should be a `schemes/` directory with a selection of schemes of both formats for examples.
Feel free to add your own preferred scheme to that directory.
Arguments:
&lt;schemename&gt;: The name of a color scheme. ct will try to first load it as an .ini file color scheme
If that fails, it will look for it as a .json file color scheme
If that fails, it will look for it as an .itermcolors file color scheme.
Options:
-?, --help : Display this help message
-c, --current : Print the color table for the currently applied scheme
-q, --quiet : Don't print the color table after applying
-e, --errors : Report scheme parsing errors on the console
-d, --defaults : Apply the scheme to only the defaults in the registry
-b, --both : Apply the scheme to both the current console and the defaults.
-x, --xterm : Set the colors using VT sequences. Used for setting the colors in WSL.
Only works in Windows versions &gt;= 17048.
-s, --schemes : Displays all available schemes
-l, --location : Displays the full path to the schemes directory
-v, --version : Display the version number
-o, --output &lt;filename&gt; : output the current color table to an file (in .ini format)
Available importers:
{0}</value>
</data>
<data name="WroteToDefaults" xml:space="preserve">
<value>Wrote selected scheme to the defaults.</value>
</data>
</root>

View file

@ -0,0 +1,106 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using ColorTool.SchemeParsers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using static ColorTool.ConsoleAPI;
namespace ColorTool
{
static class SchemeManager
{
public static IEnumerable<string> GetSearchPaths(string schemeName, string extension)
{
// Search order, for argument "name", where 'exe' is the dir of the exe.
// 1. ./name
// 2. ./name.ext
// 3. ./schemes/name
// 4. ./schemes/name.ext
// 5. exe/schemes/name
// 6. exe/schemes/name.ext
// 7. name (as an absolute path)
string cwd = "./";
yield return cwd + schemeName;
string filename = schemeName + extension;
yield return cwd + filename;
string cwdSchemes = "./schemes/";
yield return cwdSchemes + schemeName;
yield return cwdSchemes + filename;
string exeDir = Directory.GetParent(System.Reflection.Assembly.GetEntryAssembly().Location).FullName;
string exeSchemes = exeDir + "/schemes/";
yield return exeSchemes + schemeName;
yield return exeSchemes + filename;
yield return schemeName;
}
public static void PrintSchemesDirectory()
{
string schemeDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes");
Console.WriteLine(schemeDirectory);
}
public static void PrintSchemes()
{
var schemeDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes");
if (Directory.Exists(schemeDirectory))
{
IntPtr handle = GetStdOutputHandle();
GetConsoleMode(handle, out var mode);
SetConsoleMode(handle, mode | 0x4);
int consoleWidth = Console.WindowWidth;
string fgText = " gYw ";
foreach (string schemeName in Directory.GetFiles(schemeDirectory).Select(Path.GetFileName))
{
ColorScheme colorScheme = GetScheme(schemeName, false);
if (colorScheme != null)
{
string colors = string.Empty;
for (var index = 0; index < 8; index++)
{
var color = colorScheme[index];
// Set the background color to the color in the scheme, plus some text to show how it looks
colors += $"\x1b[48;2;{color.R};{color.G};{color.B}m{fgText}";
}
// Align scheme colors right, or on newline if it doesn't fit
int schemeTextLength = fgText.Length * 8;
int bufferLength = consoleWidth - (schemeName.Length + schemeTextLength);
string bufferString = bufferLength >= 0
? new string(' ', bufferLength)
: "\n" + new string(' ', consoleWidth - schemeTextLength);
string outputString = schemeName + bufferString + colors;
Console.WriteLine(outputString);
Console.ResetColor();
}
}
}
}
public static ColorScheme GetScheme(string schemeName, bool reportErrors = false)
{
return GetParsers()
.Where(parser => parser.CanParse(schemeName))
.Select(parser => parser.ParseScheme(schemeName, reportErrors))
.FirstOrDefault();
}
public static IEnumerable<ISchemeParser> GetParsers()
{
return typeof(Program).Assembly.GetTypes()
.Where(t => !t.IsAbstract && typeof(ISchemeParser).IsAssignableFrom(t))
.Select(t => (ISchemeParser)Activator.CreateInstance(t));
}
}
}

View file

@ -0,0 +1,14 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
namespace ColorTool.SchemeParsers
{
interface ISchemeParser
{
string Name { get; }
bool CanParse(string schemeName);
ColorScheme ParseScheme(string schemeName, bool reportErrors = false);
}
}

View file

@ -0,0 +1,193 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using System;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections.Generic;
using static ColorTool.ConsoleAPI;
namespace ColorTool.SchemeParsers
{
class IniSchemeParser : ISchemeParser
{
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
private const string FileExtension = ".ini";
// These are in Windows Color table order - BRG, not RGB.
internal static readonly IReadOnlyList<string> ColorNames = new[]
{
"DARK_BLACK",
"DARK_BLUE",
"DARK_GREEN",
"DARK_CYAN",
"DARK_RED",
"DARK_MAGENTA",
"DARK_YELLOW",
"DARK_WHITE",
"BRIGHT_BLACK",
"BRIGHT_BLUE",
"BRIGHT_GREEN",
"BRIGHT_CYAN",
"BRIGHT_RED",
"BRIGHT_MAGENTA",
"BRIGHT_YELLOW",
"BRIGHT_WHITE"
};
public string Name { get; } = "INI File Parser";
public bool CanParse(string schemeName) =>
string.Equals(Path.GetExtension(schemeName), FileExtension, StringComparison.OrdinalIgnoreCase);
public ColorScheme ParseScheme(string schemeName, bool reportErrors = false)
{
bool success = true;
string filename = FindIniScheme(schemeName);
if (filename == null) return null;
string[] tableStrings = new string[ColorTableSize];
uint[] colorTable = null;
uint? foregroundColor = null;
uint? backgroundColor = null;
uint? popupForegroundColor = null;
uint? popupBackgroundColor = null;
for (int i = 0; i < ColorTableSize; i++)
{
string name = ColorNames[i];
StringBuilder buffer = new StringBuilder(512);
GetPrivateProfileString("table", name, null, buffer, 512, filename);
tableStrings[i] = buffer.ToString();
if (tableStrings[i].Length <= 0)
{
success = false;
if (reportErrors)
{
Console.WriteLine(string.Format(Resources.IniParseError, filename, name, tableStrings[i]));
}
break;
}
}
if (success)
{
try
{
colorTable = new uint[ColorTableSize];
for (int i = 0; i < ColorTableSize; i++)
{
colorTable[i] = ParseColor(tableStrings[i]);
}
if (ReadAttributes("popup", out var foreground, out var background))
{
var foregroundIndex = (ColorNames as IList<string>).IndexOf(foreground);
var backgroundIndex = (ColorNames as IList<string>).IndexOf(background);
if (foregroundIndex != -1 && backgroundIndex != -1)
{
popupForegroundColor = colorTable[foregroundIndex];
popupBackgroundColor = colorTable[backgroundIndex];
}
}
if (ReadAttributes("screen", out foreground, out background))
{
var foregroundIndex = (ColorNames as IList<string>).IndexOf(foreground);
var backgroundIndex = (ColorNames as IList<string>).IndexOf(background);
if (foregroundIndex != -1 && backgroundIndex != -1)
{
foregroundColor = colorTable[foregroundIndex];
backgroundColor = colorTable[backgroundIndex];
}
}
}
catch (Exception /*e*/)
{
if (reportErrors)
{
Console.WriteLine(string.Format(Resources.IniLoadError, filename));
}
colorTable = null;
}
}
if (colorTable != null)
{
var consoleAttributes = new ConsoleAttributes(backgroundColor, foregroundColor, popupBackgroundColor, popupForegroundColor);
return new ColorScheme(colorTable, consoleAttributes);
}
else
{
return null;
}
bool ReadAttributes(string section, out string foreground, out string background)
{
foreground = null;
background = null;
StringBuilder buffer = new StringBuilder(512);
GetPrivateProfileString(section, "FOREGROUND", null, buffer, 512, filename);
foreground = buffer.ToString();
if (!ColorNames.Contains(foreground))
return false;
buffer = new StringBuilder(512);
GetPrivateProfileString(section, "BACKGROUND", null, buffer, 512, filename);
background = buffer.ToString();
if (!ColorNames.Contains(background))
return false;
return true;
}
}
private static uint ParseHex(string arg)
{
System.Drawing.Color col = System.Drawing.ColorTranslator.FromHtml(arg);
return RGB(col.R, col.G, col.B);
}
private static uint ParseRgb(string arg)
{
int[] components = { 0, 0, 0 };
string[] args = arg.Split(',');
if (args.Length != components.Length) throw new Exception("Invalid color format \"" + arg + "\"");
if (args.Length != 3) throw new Exception("Invalid color format \"" + arg + "\"");
for (int i = 0; i < args.Length; i++)
{
components[i] = Int32.Parse(args[i]);
}
return RGB(components[0], components[1], components[2]);
}
private static uint ParseColor(string arg)
{
if (arg[0] == '#')
{
return ParseHex(arg.Substring(1));
}
else
{
return ParseRgb(arg);
}
}
private static string FindIniScheme(string schemeName)
{
return SchemeManager.GetSearchPaths(schemeName, FileExtension).FirstOrDefault(File.Exists);
}
}
}

View file

@ -0,0 +1,141 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Xml;
using static ColorTool.ConsoleAPI;
namespace ColorTool.SchemeParsers
{
class JsonParser : ISchemeParser
{
private const string FileExtension = ".json";
private static readonly IReadOnlyList<string> ConcfgColorNames = new[]
{
"black", // Dark Black
"dark_blue", // Dark Blue
"dark_green", // Dark Green
"dark_cyan", // Dark Cyan
"dark_red", // Dark Red
"dark_magenta", // Dark Magenta
"dark_yellow", // Dark Yellow
"gray", // Dark White
"dark_gray", // Bright Black
"blue", // Bright Blue
"green", // Bright Green
"cyan", // Bright Cyan
"red", // Bright Red
"magenta", // Bright Magenta
"yellow", // Bright Yellow
"white" // Bright White
};
public string Name { get; } = "concfg Parser";
public bool CanParse(string schemeName) =>
string.Equals(Path.GetExtension(schemeName), FileExtension, StringComparison.OrdinalIgnoreCase);
public ColorScheme ParseScheme(string schemeName, bool reportErrors = false)
{
XmlDocument xmlDoc = LoadJsonFile(schemeName);
if (xmlDoc == null) return null;
try
{
XmlNode root = xmlDoc.DocumentElement;
XmlNodeList children = root.ChildNodes;
uint[] colorTable = new uint[ColorTableSize]; ;
for (int i = 0; i < ColorTableSize; i++)
{
string name = ConcfgColorNames[i];
var node = children.OfType<XmlNode>().Where(n => n.Name == name).Single();
colorTable[i] = ParseColor(node.InnerText);
}
uint? popupForeground = null;
uint? popupBackground = null;
var popupNode = children.OfType<XmlNode>().Where(n => n.Name == "popup_colors").SingleOrDefault();
if (popupNode != null)
{
var parts = popupNode.InnerText.Split(',');
if (parts.Length == 2)
{
var foregroundIndex = (ConcfgColorNames as IList<string>).IndexOf(parts[0]);
var backgroundIndex = (ConcfgColorNames as IList<string>).IndexOf(parts[1]);
if (foregroundIndex != -1 && backgroundIndex != -1)
{
popupForeground = colorTable[foregroundIndex];
popupBackground = colorTable[backgroundIndex];
}
}
}
uint? screenForeground = null;
uint? screenBackground = null;
var screenNode = children.OfType<XmlNode>().Where(n => n.Name == "screen_colors").SingleOrDefault();
if (screenNode != null)
{
var parts = screenNode.InnerText.Split(',');
if (parts.Length == 2)
{
var foregroundIndex = (ConcfgColorNames as IList<string>).IndexOf(parts[0]);
var backgroundIndex = (ConcfgColorNames as IList<string>).IndexOf(parts[1]);
if (foregroundIndex != -1 && backgroundIndex != -1)
{
screenForeground = colorTable[foregroundIndex];
screenBackground = colorTable[backgroundIndex];
}
}
}
var consoleAttributes = new ConsoleAttributes(screenBackground, screenForeground, popupBackground, popupForeground);
return new ColorScheme(colorTable, consoleAttributes);
}
catch (Exception /*e*/)
{
if (reportErrors)
{
Console.WriteLine("failed to load json scheme");
}
return null;
}
}
private static uint ParseColor(string arg)
{
System.Drawing.Color col = System.Drawing.ColorTranslator.FromHtml(arg);
return RGB(col.R, col.G, col.B);
}
private static XmlDocument LoadJsonFile(string schemeName)
{
XmlDocument xmlDoc = new XmlDocument();
foreach (string path in SchemeManager.GetSearchPaths(schemeName, FileExtension)
.Where(File.Exists))
{
try
{
var data = File.ReadAllBytes(path);
var reader = JsonReaderWriterFactory.CreateJsonReader(data, System.Xml.XmlDictionaryReaderQuotas.Max);
xmlDoc.Load(reader);
return xmlDoc;
}
catch (XmlException /*e*/) { /* failed to parse */ }
catch (IOException /*e*/) { /* failed to find */ }
catch (UnauthorizedAccessException /*e*/) { /* unauthorized */ }
}
return null;
}
}
}

View file

@ -0,0 +1,147 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
using static ColorTool.ConsoleAPI;
namespace ColorTool.SchemeParsers
{
class XmlSchemeParser : ISchemeParser
{
// In Windows Color Table order
private static readonly string[] PListColorNames =
{
"Ansi 0 Color", // Dark Black
"Ansi 4 Color", // Dark Blue
"Ansi 2 Color", // Dark Green
"Ansi 6 Color", // Dark Cyan
"Ansi 1 Color", // Dark Red
"Ansi 5 Color", // Dark Magenta
"Ansi 3 Color", // Dark Yellow
"Ansi 7 Color", // Dark White
"Ansi 8 Color", // Bright Black
"Ansi 12 Color", // Bright Blue
"Ansi 10 Color", // Bright Green
"Ansi 14 Color", // Bright Cyan
"Ansi 9 Color", // Bright Red
"Ansi 13 Color", // Bright Magenta
"Ansi 11 Color", // Bright Yellow
"Ansi 15 Color" // Bright White
};
private const string ForegroundKey = "Foreground Color";
private const string BackgroundKey = "Background Color";
private const string RedKey = "Red Component";
private const string GreenKey = "Green Component";
private const string BlueKey = "Blue Component";
private const string FileExtension = ".itermcolors";
public string Name { get; } = "iTerm Parser";
public bool CanParse(string schemeName) =>
string.Equals(Path.GetExtension(schemeName), FileExtension, StringComparison.OrdinalIgnoreCase);
public ColorScheme ParseScheme(string schemeName, bool reportErrors = false)
{
XmlDocument xmlDoc = LoadXmlScheme(schemeName); // Create an XML document object
if (xmlDoc == null) return null;
XmlNode root = xmlDoc.GetElementsByTagName("dict")[0];
XmlNodeList children = root.ChildNodes;
uint[] colorTable = new uint[ColorTableSize];
uint? fgColor = null, bgColor = null;
int colorsFound = 0;
bool success = false;
foreach (var tableEntry in children.OfType<XmlNode>().Where(_ => _.Name == "key"))
{
uint rgb = 0;
int index = -1;
XmlNode components = tableEntry.NextSibling;
success = ParseRgbFromXml(components, ref rgb);
if (!success) { break; }
else if (tableEntry.InnerText == ForegroundKey) { fgColor = rgb; }
else if (tableEntry.InnerText == BackgroundKey) { bgColor = rgb; }
else if (-1 != (index = Array.IndexOf(PListColorNames, tableEntry.InnerText)))
{ colorTable[index] = rgb; colorsFound++; }
}
if (colorsFound < ColorTableSize)
{
if (reportErrors)
{
Console.WriteLine(Resources.InvalidNumberOfColors);
}
success = false;
}
if (!success)
{
return null;
}
var consoleAttributes = new ConsoleAttributes(bgColor, fgColor, null, null);
return new ColorScheme(colorTable, consoleAttributes);
}
private static bool ParseRgbFromXml(XmlNode components, ref uint rgb)
{
int r = -1;
int g = -1;
int b = -1;
foreach (XmlNode c in components.ChildNodes)
{
if (c.Name == "key")
{
if (c.InnerText == RedKey)
{
r = (int)(255 * Convert.ToDouble(c.NextSibling.InnerText, CultureInfo.InvariantCulture));
}
else if (c.InnerText == GreenKey)
{
g = (int)(255 * Convert.ToDouble(c.NextSibling.InnerText, CultureInfo.InvariantCulture));
}
else if (c.InnerText == BlueKey)
{
b = (int)(255 * Convert.ToDouble(c.NextSibling.InnerText, CultureInfo.InvariantCulture));
}
else
{
continue;
}
}
}
if (r < 0 || g < 0 || b < 0)
{
Console.WriteLine(Resources.InvalidColor);
return false;
}
rgb = RGB(r, g, b);
return true;
}
private static XmlDocument LoadXmlScheme(string schemeName)
{
XmlDocument xmlDoc = new XmlDocument(); // Create an XML document object
foreach (string path in SchemeManager.GetSearchPaths(schemeName, FileExtension)
.Where(File.Exists))
{
try
{
xmlDoc.Load(path);
return xmlDoc;
}
catch (XmlException /*e*/) { /* failed to parse */ }
catch (IOException /*e*/) { /* failed to find */ }
catch (UnauthorizedAccessException /*e*/) { /* unauthorized */ }
}
return null;
}
}
}

View file

@ -0,0 +1,66 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
using ColorTool.SchemeParsers;
using System;
using static ColorTool.ConsoleAPI;
namespace ColorTool.SchemeWriters
{
class IniSchemeWriter
{
public bool ExportCurrentAsIni(string outputPath)
{
CONSOLE_SCREEN_BUFFER_INFO_EX csbiex = CONSOLE_SCREEN_BUFFER_INFO_EX.Create();
IntPtr hOut = GetStdOutputHandle();
bool success = GetConsoleScreenBufferInfoEx(hOut, ref csbiex);
if (success)
{
try
{
// StreamWriter can fail for a variety of file system reasons so catch exceptions and print message.
using (System.IO.StreamWriter file = new System.IO.StreamWriter(outputPath))
{
file.WriteLine("[table]");
for (int i = 0; i < 16; i++)
{
string line = IniSchemeParser.ColorNames[i];
line += " = ";
uint color = csbiex.ColorTable[i];
uint r = color & (0x000000ff);
uint g = (color & (0x0000ff00)) >> 8;
uint b = (color & (0x00ff0000)) >> 16;
line += r + "," + g + "," + b;
file.WriteLine(line);
}
file.WriteLine();
file.WriteLine("[screen]");
var forgroundIndex = csbiex.wAttributes & 0xF;
var backgroundIndex = csbiex.wAttributes >> 4;
file.WriteLine($"FOREGROUND = {IniSchemeParser.ColorNames[forgroundIndex]}");
file.WriteLine($"BACKGROUND = {IniSchemeParser.ColorNames[backgroundIndex]}");
file.WriteLine();
file.WriteLine("[popup]");
forgroundIndex = csbiex.wPopupAttributes & 0xF;
backgroundIndex = csbiex.wPopupAttributes >> 4;
file.WriteLine($"FOREGROUND = {IniSchemeParser.ColorNames[forgroundIndex]}");
file.WriteLine($"BACKGROUND = {IniSchemeParser.ColorNames[backgroundIndex]}");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
else
{
Console.WriteLine("Failed to get console information.");
}
return success;
}
}
}

View file

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

View file

@ -0,0 +1,54 @@
# ColorTool
ColorTool makes it easy to change the Windows console to your desired scheme. Includes support for iTerm themes!
```
Usage:
colortool.exe [options] <schemename>
ColorTool is a utility for helping to set the color palette of the Windows Console.
By default, applies the colors in the specified .itermcolors or .ini file to the current console window.
This does NOT save the properties automatically. For that, you'll need to open the properties sheet and hit "Ok".
Included should be a `schemes/` directory with a selection of schemes of both formats for examples.
Feel free to add your own preferred scheme to that directory.
Arguments:
<schemename>: The name of a color scheme. ct will try to first load it as an .itermcolors color scheme.
If that fails, it will look for it as an .ini file color scheme.
Options:
-?, --help : Display this help message
-c, --current : Print the color table for the currently applied scheme
-q, --quiet : Don't print the color table after applying
-d, --defaults : Apply the scheme to only the defaults in the registry
-b, --both : Apply the scheme to both the current console and the defaults.
-s, --schemes : Display all available schemes
-v, --version : Display the version number
```
## Included Schemes
Included are two important color schemes in .ini file format - `cmd-legacy` and `campbell`.
* `cmd-legacy` is the legacy color scheme of the Windows Console, before July 2017
* `campbell` is the new default scheme used by the Windows Console Host, as of the Fall Creator's Update.
There are a few other schemes in that directory in both .ini format and .itermcolors.
## Adding Schemes
You can also add color schemes to the colortool easily. Take any existing scheme in `.itermcolors` format, and paste it in the `schemes/` directory. Or just cd into a directory containing `*.itermcolors` files before running the colortool.
I recommend the excellent [iTerm2-Color-Schemes](https://github.com/mbadolato/iTerm2-Color-Schemes) repo, which has TONS of schemes to choose from, and previews.
You can also easily visually edit `.itermcolors` color schemes using [terminal.sexy](https://terminal.sexy). Use the **Import** and **Export** tabs with `iTerm2` as the format.
## Installing
Just [download the latest colortool release](https://github.com/Microsoft/console/releases) and extract the zip file.
## Building
Either build with Visual Studio, or use the included `build.bat` from the command line to try and auto-detect your msbuild version.
## Contributing
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

View file

@ -0,0 +1,51 @@
Third Party Notices
===================
This software is based on or incorporates material from the projects listed below (collectively, “Third-Party Code”). Please Note: Microsoft is not the original author of the Third-Party Code. The original copyright notice and license text under which Microsoft received the Third-Party Code are set forth below. Such licenses and notices are provided solely for your information. Unless otherwise noted below, Microsoft, not the third party, licenses this Third-Party Code to you under the terms by which you received the Microsoft software or the service. Microsoft reserves all other rights not expressly granted, whether by implication, estoppel or otherwise.
Do Not Translate or Localize
One Half Dark and One Half Light Schemes
----------------------------------------
Copyright (c) 2016 Son A. Pham <sp@sonpham.me>
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.
Solarized Dark and Light Schemes
--------------------------------
Copyright (c) 2011 Ethan Schoonover
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,14 @@
@echo off
rem all.bat
rem This tool can be used to iterate over all the schemes you have installed
rem To help find one that you like. Simply press Ctrl+C when you get to one you like.
rem Note: You will likely destroy your current console window's history.
rem Only the most recent theme is visible in the console.
rem All of the previously viewed tables will display the current scheme's colors.
for %%i in (schemes\*) do (
echo %%i
.\colortool.exe "%%i"
pause
)

View file

@ -0,0 +1,79 @@
@echo off
rem Add path to MSBuild Binaries
set MSBUILD=()
for /f "usebackq tokens=*" %%f in (`where.exe msbuild.exe 2^>nul`) do (
set MSBUILD="%%~ff"
goto :FOUND_MSBUILD
)
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe" (
set MSBUILD="%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe"
goto :FOUND_MSBUILD
)
if exist "%ProgramFiles%\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe" (
set MSBUILD="%ProgramFiles%\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe"
goto :FOUND_MSBUILD
)
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild.exe" (
set MSBUILD="%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild.exe"
goto :FOUND_MSBUILD
)
if exist "%ProgramFiles%\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild.exe" (
set MSBUILD="%ProgramFiles%\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild.exe"
goto :FOUND_MSBUILD
)
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe" (
set MSBUILD="%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe"
goto :FOUND_MSBUILD
)
if exist "%ProgramFiles%\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe" (
set MSBUILD="%ProgramFiles%\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe"
goto :FOUND_MSBUILD
)
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe" (
set MSBUILD="%ProgramFiles(x86)%\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe"
goto :FOUND_MSBUILD
)
if exist "%ProgramFiles(x86)%\MSBuild\14.0\bin" (
set MSBUILD="%ProgramFiles(x86)%\MSBuild\14.0\bin\msbuild.exe"
goto :FOUND_MSBUILD
)
if exist "%ProgramFiles%\MSBuild\14.0\bin" (
set MSBUILD="%ProgramFiles%\MSBuild\14.0\bin\msbuild.exe"
goto :FOUND_MSBUILD
)
if %MSBUILD%==() (
echo "I couldn't find MSBuild on your PC. Make sure it's installed somewhere, and if it's not in the above if statements (in build.bat), add it."
goto :EXIT
)
:FOUND_MSBUILD
set _MSBUILD_TARGET=Build
set _MSBUILD_CONFIG=Debug
:ARGS_LOOP
if (%1) == () goto :POST_ARGS_LOOP
if (%1) == (clean) (
set _MSBUILD_TARGET=Clean,Build
)
if (%1) == (rel) (
set _MSBUILD_CONFIG=Release
)
shift
goto :ARGS_LOOP
:POST_ARGS_LOOP
%MSBUILD% %~dp0ColorTool.sln /t:%_MSBUILD_TARGET% /m /nr:true /p:Configuration=%_MSBUILD_CONFIG%
if (%ERRORLEVEL%) == (0) (
echo.
echo Created exe in:
echo %~dp0ColorTool\bin\%_MSBUILD_CONFIG%\colortool.exe
echo.
echo Copying exe to root of project...
copy %~dp0ColorTool\bin\%_MSBUILD_CONFIG%\colortool.exe %~dp0colortool.exe
echo Done.
echo.
)
:EXIT

View file

@ -0,0 +1,376 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Name: One Half Dark
Author: Son A. Pham sp@sonpham.me
Url: https://github.com/sonph/onehalf
License: The MIT License (MIT)
Copyright (c) 2016 Son A. Pham sp@sonpham.me
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.
A dark iTerm color scheme based on Atom's One. See github.com/sonph/onehalf
for installation instructions, a light color scheme, and versions for other
editors/terminals such as (Neo)Vim and Sublime Text.
-->
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Ansi 0 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.203921568627</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.172549019608</real>
<key>Red Component</key>
<real>0.156862745098</real>
</dict>
<key>Ansi 1 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.458823529412</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.423529411765</real>
<key>Red Component</key>
<real>0.878431372549</real>
</dict>
<key>Ansi 10 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.474509803922</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.764705882353</real>
<key>Red Component</key>
<real>0.596078431373</real>
</dict>
<key>Ansi 11 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.482352941176</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.752941176471</real>
<key>Red Component</key>
<real>0.898039215686</real>
</dict>
<key>Ansi 12 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.937254901961</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.686274509804</real>
<key>Red Component</key>
<real>0.380392156863</real>
</dict>
<key>Ansi 13 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.866666666667</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.470588235294</real>
<key>Red Component</key>
<real>0.776470588235</real>
</dict>
<key>Ansi 14 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.760784313725</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.713725490196</real>
<key>Red Component</key>
<real>0.337254901961</real>
</dict>
<key>Ansi 15 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.894117647059</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.874509803922</real>
<key>Red Component</key>
<real>0.862745098039</real>
</dict>
<key>Ansi 2 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.474509803922</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.764705882353</real>
<key>Red Component</key>
<real>0.596078431373</real>
</dict>
<key>Ansi 3 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.482352941176</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.752941176471</real>
<key>Red Component</key>
<real>0.898039215686</real>
</dict>
<key>Ansi 4 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.937254901961</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.686274509804</real>
<key>Red Component</key>
<real>0.380392156863</real>
</dict>
<key>Ansi 5 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.866666666667</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.470588235294</real>
<key>Red Component</key>
<real>0.776470588235</real>
</dict>
<key>Ansi 6 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.760784313725</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.713725490196</real>
<key>Red Component</key>
<real>0.337254901961</real>
</dict>
<key>Ansi 7 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.894117647059</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.874509803922</real>
<key>Red Component</key>
<real>0.862745098039</real>
</dict>
<key>Ansi 8 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.4549019607843137</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.38823529411764707</real>
<key>Red Component</key>
<real>0.35294117647058826</real>
</dict>
<key>Ansi 9 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.458823529412</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.423529411765</real>
<key>Red Component</key>
<real>0.878431372549</real>
</dict>
<key>Background Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.203921568627</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.172549019608</real>
<key>Red Component</key>
<real>0.156862745098</real>
</dict>
<key>Badge Color</key>
<dict>
<key>Alpha Component</key>
<real>0.5</real>
<key>Blue Component</key>
<real>0.0</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.0</real>
<key>Red Component</key>
<real>1</real>
</dict>
<key>Bold Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.74901962280273438</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.69803923368453979</real>
<key>Red Component</key>
<real>0.67058825492858887</real>
</dict>
<key>Cursor Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.8</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.701960784314</real>
<key>Red Component</key>
<real>0.639215686275</real>
</dict>
<key>Cursor Guide Color</key>
<dict>
<key>Alpha Component</key>
<real>0.25</real>
<key>Blue Component</key>
<real>0.250980392157</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.211764705882</real>
<key>Red Component</key>
<real>0.192156862745</real>
</dict>
<key>Cursor Text Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.894117647059</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.874509803922</real>
<key>Red Component</key>
<real>0.862745098039</real>
</dict>
<key>Foreground Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.894117647059</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.874509803922</real>
<key>Red Component</key>
<real>0.862745098039</real>
</dict>
<key>Link Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.937254901961</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.686274509804</real>
<key>Red Component</key>
<real>0.380392156863</real>
</dict>
<key>Selected Text Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.894117647059</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.874509803922</real>
<key>Red Component</key>
<real>0.862745098039</real>
</dict>
<key>Selection Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.364705882353</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.305882352941</real>
<key>Red Component</key>
<real>0.278431372549</real>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,376 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Name: One Half Light
Author: Son A. Pham <sp@sonpham.me>
Url: https://github.com/sonph/onehalf
License: The MIT License (MIT)
Copyright (c) 2016 Son A. Pham <sp@sonpham.me>
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.
A light iTerm color scheme based on Atom's One. See github.com/sonph/onehalf
for installation instructions, a dark color scheme, and versions for other
editors/terminals such as (Neo)Vim and Sublime Text.
-->
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Ansi 0 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.258823529412</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.227450980392</real>
<key>Red Component</key>
<real>0.219607843137</real>
</dict>
<key>Ansi 1 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.286274509804</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.337254901961</real>
<key>Red Component</key>
<real>0.894117647059</real>
</dict>
<key>Ansi 10 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.474509803922</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.764705882353</real>
<key>Red Component</key>
<real>0.596078431373</real>
</dict>
<key>Ansi 11 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.482352941176</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.752941176471</real>
<key>Red Component</key>
<real>0.898039215686</real>
</dict>
<key>Ansi 12 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.937254901961</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.686274509804</real>
<key>Red Component</key>
<real>0.380392156863</real>
</dict>
<key>Ansi 13 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.866666666667</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.470588235294</real>
<key>Red Component</key>
<real>0.776470588235</real>
</dict>
<key>Ansi 14 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.760784313725</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.713725490196</real>
<key>Red Component</key>
<real>0.337254901961</real>
</dict>
<key>Ansi 15 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>1.0</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>1.0</real>
<key>Red Component</key>
<real>1.0</real>
</dict>
<key>Ansi 2 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.309803921569</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.63137254902</real>
<key>Red Component</key>
<real>0.313725490196</real>
</dict>
<key>Ansi 3 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.00392156862745</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.517647058824</real>
<key>Red Component</key>
<real>0.756862745098</real>
</dict>
<key>Ansi 4 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.737254901961</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.517647058824</real>
<key>Red Component</key>
<real>0.00392156862745</real>
</dict>
<key>Ansi 5 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.643137254902</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.149019607843</real>
<key>Red Component</key>
<real>0.650980392157</real>
</dict>
<key>Ansi 6 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.701960784314</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.592156862745</real>
<key>Red Component</key>
<real>0.0352941176471</real>
</dict>
<key>Ansi 7 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.980392156863</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.980392156863</real>
<key>Red Component</key>
<real>0.980392156863</real>
</dict>
<key>Ansi 8 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.36862745098</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.321568627451</real>
<key>Red Component</key>
<real>0.309803921569</real>
</dict>
<key>Ansi 9 Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.458823529412</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.423529411765</real>
<key>Red Component</key>
<real>0.878431372549</real>
</dict>
<key>Background Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.980392156863</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.980392156863</real>
<key>Red Component</key>
<real>0.980392156863</real>
</dict>
<key>Badge Color</key>
<dict>
<key>Alpha Component</key>
<real>0.5</real>
<key>Blue Component</key>
<real>0.0</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.0</real>
<key>Red Component</key>
<real>1</real>
</dict>
<key>Bold Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.74901962280273438</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.69803923368453979</real>
<key>Red Component</key>
<real>0.67058825492858887</real>
</dict>
<key>Cursor Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>1.0</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.807843137255</real>
<key>Red Component</key>
<real>0.749019607843</real>
</dict>
<key>Cursor Guide Color</key>
<dict>
<key>Alpha Component</key>
<real>0.25</real>
<key>Blue Component</key>
<real>0.941176470588</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.941176470588</real>
<key>Red Component</key>
<real>0.941176470588</real>
</dict>
<key>Cursor Text Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.258823529412</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.227450980392</real>
<key>Red Component</key>
<real>0.219607843137</real>
</dict>
<key>Foreground Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.258823529412</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.227450980392</real>
<key>Red Component</key>
<real>0.219607843137</real>
</dict>
<key>Link Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.737254901961</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.517647058824</real>
<key>Red Component</key>
<real>0.00392156862745</real>
</dict>
<key>Selected Text Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>0.258823529412</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.227450980392</real>
<key>Red Component</key>
<real>0.219607843137</real>
</dict>
<key>Selection Color</key>
<dict>
<key>Alpha Component</key>
<real>1</real>
<key>Blue Component</key>
<real>1.0</real>
<key>Color Space</key>
<string>Calibrated</string>
<key>Green Component</key>
<real>0.807843137255</real>
<key>Red Component</key>
<real>0.749019607843</real>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,21 @@
[table]
DARK_BLACK = 19,17,23
DARK_BLUE = 6,54,222
DARK_GREEN = 57,151,50
DARK_CYAN = 48,151,168
DARK_RED = 185,0,5
DARK_MAGENTA = 141,2,180
DARK_YELLOW = 187,182,0
DARK_WHITE = 192,190,197
BRIGHT_BLACK = 85,82,92
BRIGHT_BLUE = 62,109,253
BRIGHT_GREEN = 11,213,0
BRIGHT_CYAN = 128,205,253
BRIGHT_RED = 237,57,96
BRIGHT_MAGENTA = 198,2,253
BRIGHT_YELLOW = 255,247,149
BRIGHT_WHITE = 240,239,241
[info]
name = Campbell-Legacy
author = paulcam

View file

@ -0,0 +1,21 @@
[table]
DARK_BLACK = 12,12,12
DARK_BLUE = 0,55,218
DARK_GREEN = 19,161,14
DARK_CYAN = 58,150,221
DARK_RED = 197,15,31
DARK_MAGENTA = 136,23,152
DARK_YELLOW = 193,156,0
DARK_WHITE = 204,204,204
BRIGHT_BLACK = 118,118,118
BRIGHT_BLUE = 59,120,255
BRIGHT_GREEN = 22,198,12
BRIGHT_CYAN = 97,214,214
BRIGHT_RED = 231,72,86
BRIGHT_MAGENTA = 180,0,158
BRIGHT_YELLOW = 249,241,165
BRIGHT_WHITE = 242,242,242
[info]
name = Campbell
author = crloew

View file

@ -0,0 +1,21 @@
[table]
DARK_BLACK = 0, 0, 0
DARK_BLUE = 0, 0, 128
DARK_GREEN = 0, 128, 0
DARK_CYAN = 0, 128, 128
DARK_RED = 128, 0, 0
DARK_MAGENTA = 128, 0, 128
DARK_YELLOW = 128, 128, 0
DARK_WHITE = 192, 192, 192
BRIGHT_BLACK = 128, 128, 128
BRIGHT_BLUE = 0, 0, 255
BRIGHT_GREEN = 0, 255, 0
BRIGHT_CYAN = 0, 255, 255
BRIGHT_RED = 255, 0, 0
BRIGHT_MAGENTA = 255, 0, 255
BRIGHT_YELLOW = 255, 255, 0
BRIGHT_WHITE = 255, 255, 255
[info]
name = cmd-legacy
author = unknown

View file

@ -0,0 +1,293 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Name: Deuteranopia
Author: Craig Loewen
License: The MIT License (MIT)
Copyright (c) 2017
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.
This color scheme is targeted towards user with a form of color blindness called deuteranopia.
Some of the colors have been rearranged to make them more apparent. Most notably 'red' and 'green'
have been altered from a conventional red and green to values that will instead show a more
noticeable difference, since red and green are most frequently used in the Console for
'success' or 'error'. This scheme was designed using a tool called Color Oracle which can
be found here: http://colororacle.cartography.ch/
-->
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Ansi 0 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>0</real>
<key>Red Component</key>
<real>0</real>
</dict>
<key>Ansi 1 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>0.6</real>
<key>Red Component</key>
<real>0.6</real>
</dict>
<key>Ansi 10 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>1</real>
<key>Green Component</key>
<real>0</real>
<key>Red Component</key>
<real>0</real>
</dict>
<key>Ansi 11 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.7490196078431373</real>
<key>Green Component</key>
<real>1</real>
<key>Red Component</key>
<real>1</real>
</dict>
<key>Ansi 12 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>1</real>
<key>Green Component</key>
<real>0.5019607843137255</real>
<key>Red Component</key>
<real>0.5019607843137255</real>
</dict>
<key>Ansi 13 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.5019607843137255</real>
<key>Green Component</key>
<real>1</real>
<key>Red Component</key>
<real>1</real>
</dict>
<key>Ansi 14 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>1</real>
<key>Green Component</key>
<real>0.7490196078431373</real>
<key>Red Component</key>
<real>0.7490196078431373</real>
</dict>
<key>Ansi 15 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>1</real>
<key>Green Component</key>
<real>1</real>
<key>Red Component</key>
<real>1</real>
</dict>
<key>Ansi 2 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.6</real>
<key>Green Component</key>
<real>0</real>
<key>Red Component</key>
<real>0</real>
</dict>
<key>Ansi 3 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.45098039215686275</real>
<key>Green Component</key>
<real>0.6</real>
<key>Red Component</key>
<real>0.6</real>
</dict>
<key>Ansi 4 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.6</real>
<key>Green Component</key>
<real>0.30196078431372547</real>
<key>Red Component</key>
<real>0.30196078431372547</real>
</dict>
<key>Ansi 5 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.30196078431372547</real>
<key>Green Component</key>
<real>0.6</real>
<key>Red Component</key>
<real>0.6</real>
</dict>
<key>Ansi 6 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.6</real>
<key>Green Component</key>
<real>0.45098039215686275</real>
<key>Red Component</key>
<real>0.45098039215686275</real>
</dict>
<key>Ansi 7 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.7686274509803922</real>
<key>Green Component</key>
<real>0.7686274509803922</real>
<key>Red Component</key>
<real>0.7686274509803922</real>
</dict>
<key>Ansi 8 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.4235294117647059</real>
<key>Green Component</key>
<real>0.4235294117647059</real>
<key>Red Component</key>
<real>0.4235294117647059</real>
</dict>
<key>Ansi 9 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>1</real>
<key>Red Component</key>
<real>1</real>
</dict>
<key>Background Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>0</real>
<key>Red Component</key>
<real>0</real>
</dict>
<key>Bold Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.7686274509803922</real>
<key>Green Component</key>
<real>0.7686274509803922</real>
<key>Red Component</key>
<real>0.7686274509803922</real>
</dict>
<key>Cursor Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.7686274509803922</real>
<key>Green Component</key>
<real>0.7686274509803922</real>
<key>Red Component</key>
<real>0.7686274509803922</real>
</dict>
<key>Cursor Text Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>0</real>
<key>Red Component</key>
<real>0</real>
</dict>
<key>Foreground Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.7686274509803922</real>
<key>Green Component</key>
<real>0.7686274509803922</real>
<key>Red Component</key>
<real>0.7686274509803922</real>
</dict>
<key>Selected Text Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.7686274509803922</real>
<key>Green Component</key>
<real>0.7686274509803922</real>
<key>Red Component</key>
<real>0.7686274509803922</real>
</dict>
<key>Selection Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>0</real>
<key>Red Component</key>
<real>0</real>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,243 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Name: Solarized Dark
Author: Ethan Schoonover - ethanschoonover.com
Url: https://github.com/altercation/solarized
License: The MIT License (MIT)
Copyright (c) 2011 Ethan Schoonover
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.
A popular color scheme created by Ethan Schoonover
-->
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Ansi 0 Color</key>
<dict>
<key>Blue Component</key>
<real>0.19370138645172119</real>
<key>Green Component</key>
<real>0.15575926005840302</real>
<key>Red Component</key>
<real>0.0</real>
</dict>
<key>Ansi 1 Color</key>
<dict>
<key>Blue Component</key>
<real>0.14145714044570923</real>
<key>Green Component</key>
<real>0.10840655118227005</real>
<key>Red Component</key>
<real>0.81926977634429932</real>
</dict>
<key>Ansi 10 Color</key>
<dict>
<key>Blue Component</key>
<real>0.38298487663269043</real>
<key>Green Component</key>
<real>0.35665956139564514</real>
<key>Red Component</key>
<real>0.27671992778778076</real>
</dict>
<key>Ansi 11 Color</key>
<dict>
<key>Blue Component</key>
<real>0.43850564956665039</real>
<key>Green Component</key>
<real>0.40717673301696777</real>
<key>Red Component</key>
<real>0.32436618208885193</real>
</dict>
<key>Ansi 12 Color</key>
<dict>
<key>Blue Component</key>
<real>0.51685798168182373</real>
<key>Green Component</key>
<real>0.50962930917739868</real>
<key>Red Component</key>
<real>0.44058024883270264</real>
</dict>
<key>Ansi 13 Color</key>
<dict>
<key>Blue Component</key>
<real>0.72908437252044678</real>
<key>Green Component</key>
<real>0.33896297216415405</real>
<key>Red Component</key>
<real>0.34798634052276611</real>
</dict>
<key>Ansi 14 Color</key>
<dict>
<key>Blue Component</key>
<real>0.56363654136657715</real>
<key>Green Component</key>
<real>0.56485837697982788</real>
<key>Red Component</key>
<real>0.50599193572998047</real>
</dict>
<key>Ansi 15 Color</key>
<dict>
<key>Blue Component</key>
<real>0.86405980587005615</real>
<key>Green Component</key>
<real>0.95794391632080078</real>
<key>Red Component</key>
<real>0.98943418264389038</real>
</dict>
<key>Ansi 2 Color</key>
<dict>
<key>Blue Component</key>
<real>0.020208755508065224</real>
<key>Green Component</key>
<real>0.54115492105484009</real>
<key>Red Component</key>
<real>0.44977453351020813</real>
</dict>
<key>Ansi 3 Color</key>
<dict>
<key>Blue Component</key>
<real>0.023484811186790466</real>
<key>Green Component</key>
<real>0.46751424670219421</real>
<key>Red Component</key>
<real>0.64746475219726562</real>
</dict>
<key>Ansi 4 Color</key>
<dict>
<key>Blue Component</key>
<real>0.78231418132781982</real>
<key>Green Component</key>
<real>0.46265947818756104</real>
<key>Red Component</key>
<real>0.12754884362220764</real>
</dict>
<key>Ansi 5 Color</key>
<dict>
<key>Blue Component</key>
<real>0.43516635894775391</real>
<key>Green Component</key>
<real>0.10802463442087173</real>
<key>Red Component</key>
<real>0.77738940715789795</real>
</dict>
<key>Ansi 6 Color</key>
<dict>
<key>Blue Component</key>
<real>0.52502274513244629</real>
<key>Green Component</key>
<real>0.57082360982894897</real>
<key>Red Component</key>
<real>0.14679534733295441</real>
</dict>
<key>Ansi 7 Color</key>
<dict>
<key>Blue Component</key>
<real>0.79781103134155273</real>
<key>Green Component</key>
<real>0.89001238346099854</real>
<key>Red Component</key>
<real>0.91611063480377197</real>
</dict>
<key>Ansi 8 Color</key>
<dict>
<key>Blue Component</key>
<real>0.39215686274509803</real>
<key>Green Component</key>
<real>0.30196078431372547</real>
<key>Red Component</key>
<real>0.0</real>
</dict>
<key>Ansi 9 Color</key>
<dict>
<key>Blue Component</key>
<real>0.073530435562133789</real>
<key>Green Component</key>
<real>0.21325300633907318</real>
<key>Red Component</key>
<real>0.74176257848739624</real>
</dict>
<key>Background Color</key>
<dict>
<key>Blue Component</key>
<real>0.15170273184776306</real>
<key>Green Component</key>
<real>0.11783610284328461</real>
<key>Red Component</key>
<real>0.0</real>
</dict>
<key>Bold Color</key>
<dict>
<key>Blue Component</key>
<real>0.56363654136657715</real>
<key>Green Component</key>
<real>0.56485837697982788</real>
<key>Red Component</key>
<real>0.50599193572998047</real>
</dict>
<key>Cursor Color</key>
<dict>
<key>Blue Component</key>
<real>0.51685798168182373</real>
<key>Green Component</key>
<real>0.50962930917739868</real>
<key>Red Component</key>
<real>0.44058024883270264</real>
</dict>
<key>Cursor Text Color</key>
<dict>
<key>Blue Component</key>
<real>0.19370138645172119</real>
<key>Green Component</key>
<real>0.15575926005840302</real>
<key>Red Component</key>
<real>0.0</real>
</dict>
<key>Foreground Color</key>
<dict>
<key>Blue Component</key>
<real>0.51685798168182373</real>
<key>Green Component</key>
<real>0.50962930917739868</real>
<key>Red Component</key>
<real>0.44058024883270264</real>
</dict>
<key>Selected Text Color</key>
<dict>
<key>Blue Component</key>
<real>0.56363654136657715</real>
<key>Green Component</key>
<real>0.56485837697982788</real>
<key>Red Component</key>
<real>0.50599193572998047</real>
</dict>
<key>Selection Color</key>
<dict>
<key>Blue Component</key>
<real>0.19370138645172119</real>
<key>Green Component</key>
<real>0.15575926005840302</real>
<key>Red Component</key>
<real>0.0</real>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,289 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Name: Solarized Light
Author: Ethan Schoonover - ethanschoonover.com
Url: https://github.com/altercation/solarized
License: The MIT License (MIT)
Copyright (c) 2011 Ethan Schoonover
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.
A popular color scheme created by Ethan Schoonover with the foreground and background adjusted to the default terminal colors
-->
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Ansi 0 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.8901960784313725</real>
<key>Green Component</key>
<real>0.9647058823529412</real>
<key>Red Component</key>
<real>0.9921568627450981</real>
</dict>
<key>Ansi 1 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.1843137254901961</real>
<key>Green Component</key>
<real>0.19607843137254902</real>
<key>Red Component</key>
<real>0.8627450980392157</real>
</dict>
<key>Ansi 10 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>0.6</real>
<key>Red Component</key>
<real>0.5215686274509804</real>
</dict>
<key>Ansi 11 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>0.5372549019607843</real>
<key>Red Component</key>
<real>0.7098039215686275</real>
</dict>
<key>Ansi 12 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.8235294117647058</real>
<key>Green Component</key>
<real>0.5450980392156862</real>
<key>Red Component</key>
<real>0.14901960784313725</real>
</dict>
<key>Ansi 13 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.7686274509803922</real>
<key>Green Component</key>
<real>0.44313725490196076</real>
<key>Red Component</key>
<real>0.4235294117647059</real>
</dict>
<key>Ansi 14 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.596078431372549</real>
<key>Green Component</key>
<real>0.6313725490196078</real>
<key>Red Component</key>
<real>0.16470588235294117</real>
</dict>
<key>Ansi 15 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.4588235294117647</real>
<key>Green Component</key>
<real>0.43137254901960786</real>
<key>Red Component</key>
<real>0.34509803921568627</real>
</dict>
<key>Ansi 2 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>0.6</real>
<key>Red Component</key>
<real>0.5215686274509804</real>
</dict>
<key>Ansi 3 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0</real>
<key>Green Component</key>
<real>0.5372549019607843</real>
<key>Red Component</key>
<real>0.7098039215686275</real>
</dict>
<key>Ansi 4 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.8235294117647058</real>
<key>Green Component</key>
<real>0.5450980392156862</real>
<key>Red Component</key>
<real>0.14901960784313725</real>
</dict>
<key>Ansi 5 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.7686274509803922</real>
<key>Green Component</key>
<real>0.44313725490196076</real>
<key>Red Component</key>
<real>0.4235294117647059</real>
</dict>
<key>Ansi 6 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.596078431372549</real>
<key>Green Component</key>
<real>0.6313725490196078</real>
<key>Red Component</key>
<real>0.16470588235294117</real>
</dict>
<key>Ansi 7 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.6313725490196078</real>
<key>Green Component</key>
<real>0.6313725490196078</real>
<key>Red Component</key>
<real>0.5764705882352941</real>
</dict>
<key>Ansi 8 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.5137254901960784</real>
<key>Green Component</key>
<real>0.4823529411764706</real>
<key>Red Component</key>
<real>0.396078431372549</real>
</dict>
<key>Ansi 9 Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.1843137254901961</real>
<key>Green Component</key>
<real>0.19607843137254902</real>
<key>Red Component</key>
<real>0.8627450980392157</real>
</dict>
<key>Background Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.8901960784313725</real>
<key>Green Component</key>
<real>0.9647058823529412</real>
<key>Red Component</key>
<real>0.9921568627450981</real>
</dict>
<key>Bold Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.4588235294117647</real>
<key>Green Component</key>
<real>0.43137254901960786</real>
<key>Red Component</key>
<real>0.34509803921568627</real>
</dict>
<key>Cursor Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.4588235294117647</real>
<key>Green Component</key>
<real>0.43137254901960786</real>
<key>Red Component</key>
<real>0.34509803921568627</real>
</dict>
<key>Cursor Text Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.8901960784313725</real>
<key>Green Component</key>
<real>0.9647058823529412</real>
<key>Red Component</key>
<real>0.9921568627450981</real>
</dict>
<key>Foreground Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.4588235294117647</real>
<key>Green Component</key>
<real>0.43137254901960786</real>
<key>Red Component</key>
<real>0.34509803921568627</real>
</dict>
<key>Selected Text Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.4588235294117647</real>
<key>Green Component</key>
<real>0.43137254901960786</real>
<key>Red Component</key>
<real>0.34509803921568627</real>
</dict>
<key>Selection Color</key>
<dict>
<key>Color Space</key>
<string>sRGB</string>
<key>Blue Component</key>
<real>0.8901960784313725</real>
<key>Green Component</key>
<real>0.9647058823529412</real>
<key>Red Component</key>
<real>0.9921568627450981</real>
</dict>
</dict>
</plist>

View file

@ -0,0 +1,37 @@
REM @echo off
REM This script copies the files to have different paths to be signed and copies them back
if "%2" == "" goto :usage
if "%1" == "sign" goto :sign
if "%1" == "afterSign" goto :afterSign
goto :usage
:sign
pushd "%2"
mkdir tosign
call :checkedCopy ..\b\Release\anycpu\ColorTool.exe tosign\ColorTool.exe
popd
goto :end
:afterSign
pushd "%2"
call :checkedCopy signed\ColorTool.exe ..\b\Release\anycpu\ColorTool.exe
popd
goto :end
:checkedCopy
copy %1 %2
if %errorlevel% NEQ 0 (
popd
exit 1
)
exit /b
:usage
echo "Usage: CopySignFiles <sign| afterSign> <root of the repo>"
echo "Will copy the binary release from <root>\Release to be sent to signed"
:end

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<SignConfigXML>
<job platform="anycpu" configuration="release" dest="__RELBINPATH__\..\..\..\s\signed" jobname="Console ColorTool" approvers="miniksa;migrie;duhowett;austdi">
<file src="__RELBINPATH__\..\..\..\s\tosign\colortool.exe" signType="Authenticode" dest="__RELBINPATH__\..\..\..\s\signed\colortool.exe" />
</job>
</SignConfigXML>