Colorful.Console icon indicating copy to clipboard operation
Colorful.Console copied to clipboard

Extend to 256 colors limit in Windows 10 Anniversary Update

Open AlexeiScherbakov opened this issue 8 years ago • 13 comments

Windows 10 Anniversary Update can use VT100 terminal codes. (Enabled by setting flag ENABLE_VIRTUAL_TERMINAL_PROCESSING by SetConsoleMode) and have 256 extended colors.

Howto: http://stackoverflow.com/a/43321133/7815105 https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx

Sample (uses indexes) ` class Program { [DllImport( "kernel32.dll", SetLastError = true )] public static extern bool SetConsoleMode( IntPtr hConsoleHandle, int mode ); [DllImport( "kernel32.dll", SetLastError = true )] public static extern bool GetConsoleMode( IntPtr handle, out int mode ); [DllImport( "kernel32.dll", SetLastError = true )] public static extern IntPtr GetStdHandle( int handle );

	static void Main( string[] args )
	{
		var handle = GetStdHandle( -11 );
		int mode;
		GetConsoleMode( handle, out mode );
		SetConsoleMode( handle, mode | 0x4 );

		for (int i=0;i<255;i++ )
		{
			Console.Write( "\x1b[48;5;" + i + "m*" );
		}

		Console.ReadLine();
	}
}

` default

Also color can be set in r,g,b mode but it is replaced to nearest of 256.

AlexeiScherbakov avatar Apr 10 '17 10:04 AlexeiScherbakov

rate it request an implementation it

0xF6 avatar May 17 '17 00:05 0xF6

[Apologies for the delayed reply!]

Thanks for the suggestion. This seems like a simple thing to implement, and I'm not opposed to doing it. However, I don't have Windows 10 installed, and wouldn't be able to test it. I can think of 2 ways of proceeding if we want to implement this:

  1. I can make the change in a separate branch, and then someone else could test in Windows 10.
  2. Someone who has an install of Windows 10 with the Anniversary Update handy could make these changes and submit a PR.

I think that option 2 is much better than option 1. In either case, we'd need to implement this feature in such a way that it is compatible with other versions of Windows, e.g. (from the MSDN page you linked to):

DWORD dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
DWORD dwRequestedInModes = ENABLE_VIRTUAL_TERMINAL_INPUT;

DWORD dwOutMode = dwOriginalOutMode | dwRequestedOutModes;
if (!SetConsoleMode(hOut, dwOutMode))
{
    // we failed to set both modes, try to step down mode gracefully.
    dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    dwOutMode = dwOriginalOutMode | dwRequestedOutModes;
    if (!SetConsoleMode(hOut, dwOutMode))
    {
        // Failed to set any VT mode, can't do anything here.
        return -1;
    }
}

DWORD dwInMode = dwOriginalInMode | ENABLE_VIRTUAL_TERMINAL_INPUT;
if (!SetConsoleMode(hIn, dwInMode))
{
    // Failed to set VT input mode, can't do anything here.
    return -1;
}

Anyway, thanks again for the suggestion!

tomakita avatar Jun 17 '17 20:06 tomakita

I'm new for this library, if you point me "right" way to add platform depended code - I can add this feature

17 Июн 2017 г. 23:10 пользователь "Tom Akita" [email protected] написал:

Thanks for the suggestion. This seems like a simple thing to implement, and I'm not opposed to doing it. However, I don't have Windows 10 installed, and wouldn't be able to test it. I can think of 2 ways of proceeding if we want to implement this:

  1. I can make the change in a separate branch, and then someone else could test in Windows 10.
  2. Someone who has an install of Windows 10 with the Anniversary Update handy could make these changes and submit a PR.

I think that option 2 is much better than option 1. In either case, we'd need to implement this feature in such a way that it is compatible with other versions of Windows, e.g. (from the MSDN page you linked to):

DWORD dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN; DWORD dwRequestedInModes = ENABLE_VIRTUAL_TERMINAL_INPUT;

DWORD dwOutMode = dwOriginalOutMode | dwRequestedOutModes; if (!SetConsoleMode(hOut, dwOutMode)) { // we failed to set both modes, try to step down mode gracefully. dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING; dwOutMode = dwOriginalOutMode | dwRequestedOutModes; if (!SetConsoleMode(hOut, dwOutMode)) { // Failed to set any VT mode, can't do anything here. return -1; } }

DWORD dwInMode = dwOriginalInMode | ENABLE_VIRTUAL_TERMINAL_INPUT; if (!SetConsoleMode(hIn, dwInMode)) { // Failed to set VT input mode, can't do anything here. return -1; }

Anyway, thanks again for the suggestion!

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/tomakita/Colorful.Console/issues/24#issuecomment-309237306, or mute the thread https://github.com/notifications/unsubscribe-auth/AIQ7OwTYL84Wro_wrmeps1Hu_qQu4K5Kks5sFDKjgaJpZM4M4mJS .

AlexeiScherbakov avatar Jun 17 '17 20:06 AlexeiScherbakov

That sounds great! The best place to add this sort of functionality would probably be in the static constructor of the Colorful.Console class:

https://github.com/tomakita/Colorful.Console/blob/master/src/Colorful.Console/ColorfulConsoleFront.cs#L298

This will run each time the application loads. Let me know if I can help in any other way, and thanks for making this change!

tomakita avatar Jun 18 '17 02:06 tomakita

Regarding the platform-dependent code, I think it's safe to add [DllImport]s as if the code will run on Windows, and then check at runtime whether or not they should be called.

https://github.com/serilog/serilog-sinks-console/blob/dev/src/Serilog.Sinks.Console/Sinks/SystemConsole/Platform/WindowsConsole.cs

..and the accompanying CSPROJ file demonstrate how we're going to do this for Serilog.

HTH!

nblumhardt avatar Jun 19 '17 21:06 nblumhardt

Thanks @nblumhardt, this is very helpful!

tomakita avatar Jun 19 '17 22:06 tomakita

Windows 10 have some version detection issues: https://msdn.microsoft.com/en-ca/library/windows/desktop/dn481241(v=vs.85).aspx All version detection functions are now deprecated - Windows looks at app.manifest and if Windows 10 is not explicitly supported - version functions return Windows 8.1 instead. Before turning on Virtual Terminal commands we must detect OS. In this code it is maked by detection of Windows RT class 'Windows.ApplicationModel.AppExtensions.AppExtensionCatalog' which is exist after Anniversary Update

`internal static class OperationSystemDetector { private static readonly bool _isAnniversaryUpdate;

    static OperationSystemDetector()
    {
        // OS Detection for all CLR implementations (.NET Framework,Mono,.NET Core)
        var windir = Environment.GetEnvironmentVariable("windir");

        if ((!string.IsNullOrWhiteSpace(windir)) && windir.Contains(@"\") && Directory.Exists(windir))
        {
            // windows
            _isAnniversaryUpdate = DetectAnniversaryUpdate();
        }
        else if (File.Exists("/proc/sys/kernel/ostype"))
        {
            string osType = File.ReadAllText(@"/proc/sys/kernel/ostype");
            if (osType.StartsWith("Linux", StringComparison.OrdinalIgnoreCase))
            {
                // linux
            }
        }
        else if (File.Exists(@"/System/Library/CoreServices/SystemVersion.plist"))
        {
            // Mac OS
        }

    }

    public static bool IsAnniversaryUpdate
    {
        get { return _isAnniversaryUpdate; }
    }

    /// <summary>
    /// ALL version info functions are DEPRECATED since Windows 10
    /// https://msdn.microsoft.com/en-ca/library/windows/desktop/dn481241(v=vs.85).aspx
    /// this code modified version of code:
    /// http://answers.unity3d.com/questions/1249727/detect-if-windows-10-anniversary-version-number.html
    /// </summary>
    /// <returns></returns>
    private static bool DetectAnniversaryUpdate()
    {
        const string kAppExtensionClassName = "Windows.ApplicationModel.AppExtensions.AppExtensionCatalog";
        var classNameHString = IntPtr.Zero;
        bool ok = false;
        try
        {
            if (WindowsCreateString(kAppExtensionClassName, kAppExtensionClassName.Length, out classNameHString) == 0)
            {
                IntPtr appExtensionCatalogStatics;
                var IID_IAppExtensionCatalogStatics = new Guid(1010198154, 24344, 20235, 156, 229, 202, 182, 29, 25, 111, 17);

                if (RoGetActivationFactory(classNameHString, ref IID_IAppExtensionCatalogStatics, out appExtensionCatalogStatics) == 0)
                {
                    if (appExtensionCatalogStatics != IntPtr.Zero)
                    {
                        Marshal.Release(appExtensionCatalogStatics);
                        ok = true;
                    }
                }
            }
        }
        finally
        {
            if (IntPtr.Zero != classNameHString)
            {
                WindowsDeleteString(classNameHString);
            }
        }
        return ok;
    }


    [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll")]
    private static extern int WindowsCreateString([MarshalAs(UnmanagedType.LPWStr)]string sourceString, int stringLength, out IntPtr hstring);

    [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll")]
    private static extern int WindowsDeleteString(IntPtr hstring);

    [DllImport("api-ms-win-core-winrt-l1-1-0.dll")]
    private static extern int RoGetActivationFactory(IntPtr className, ref Guid guid, out IntPtr instance);
}`

AlexeiScherbakov avatar Jun 20 '17 07:06 AlexeiScherbakov

I added basic support. Also I found that current color replace functionality is not working if color is setted by VT command. I don't know how to integrate it in Console class because it will need frontend/backend separation, VT functionality is a completly different

AlexeiScherbakov avatar Jun 20 '17 09:06 AlexeiScherbakov

Thanks for the PR! I've been thinking about this over the past 2 weeks -- it's difficult for me to know exactly what to do here, as I can't actually run the code myself.

You mentioned that the VT functionality is not integrated into the Colorful.Console class. While this is not necessarily a problem, I do think that there is risk of confusing users if not all coloring functionality is supported by the Colorful.Console class. Still, I would love to merge this PR, as long as it has compelling benefits as-is. In other words: even though the VT functionality in this PR is not integrated with the Colorful.Console class, is it still useful? If you think it is, then I'll go ahead and merge.

Thanks again for the hard work.

All participants in this thread are welcome to chime in -- not just Alexei!

tomakita avatar Jul 03 '17 16:07 tomakita

@tomakita it would be good to get this merged as a starting point for adding support to Colorful.Console. Right now resetting the pallet after use is tricky, and the .net applications output is then screwed up. This would be a far more elegant coloring solution allowing proper colors to remain behind on the console after use even if it only works on modern platforms.

mitchcapper avatar Nov 15 '17 18:11 mitchcapper

@tomakita further I would probably work on this some after merge to start converting methods to use this instead. As we want to keep back compat support, do we want to just #define with a compiler flag for WIN10 vs normal support? I believe we could also do runtime detection as well.

mitchcapper avatar Nov 15 '17 18:11 mitchcapper

Apologies for the delay -- I've been busy. I'm going to test out the changes in https://github.com/tomakita/Colorful.Console/pull/29 this weekend, and will merge it if all goes well.

@mitchcapper I do think the compiler flag for Win10 support makes the most sense -- this is a good idea.

tomakita avatar Jun 21 '19 21:06 tomakita

I started to try and work on #29 further to get the older console switching code stripped out but the whole slot matrix is in part what this library is around. Adding the full cross plat in would be tricky too. I decided to try and go another way and start with VT commands and then start doing some Colorful.Console on top. I kept some of the syntax similar but largely went a different direction with a quick implementation.

It is the last commit on https://github.com/mitchcapper/TrueColorConsole/tree/stylesheet_support

note it is built on another PR for https://github.com/aybe/TrueColorConsole for cross-plat support. Not suggesting it except potentially as a stop gap solution for people. For my apps it worked.

mitchcapper avatar Oct 09 '20 10:10 mitchcapper