adding text decorations to console output
Asked Answered
V

6

16

I have a c# .net 3.5 application that writes text to the console using a StreamWriter. Is there a way I can add text decorations like underline and strikethrough to the text that is printed to the console? Possibly using ANSI escape sequences?

TextWriter writer = new StreamWriter(Console.OpenStandardOutput());
writer.WriteLine("some underlined text");

Thanks, PaulH

Violetteviolin answered 8/3, 2011 at 20:4 Comment(0)
R
7

The Windows console does not support ANSI escape sequences. To my knowledge, the only way to change the attributes of an output character is to call SetConsoleTextAttribute before writing the character. Or, in .NET, modify the Console.ForegroundColor or Console.BackgroundColor attributes.

It might be possible to set those properties to custom values (i.e. values not defined by ConsoleColor) with a type cast. But I don't know what good that would do you.

I don't know that I've ever seen strikethrough text on a Windows console, and it's been years since I saw underline. I suppose it's possible, but I don't know how it's done.

Runin answered 8/3, 2011 at 20:29 Comment(1)
Now with Microsoft Windows [Version 10.0.19044.2728] it does see https://mcmap.net/q/219845/-ansi-colors-and-writing-directly-to-console-output-c for example.Motch
F
26

In Windows 10 build 16257 and later:

using System;
using System.Runtime.InteropServices;

class Program
{
    const int STD_OUTPUT_HANDLE = -11;
    const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4;

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetStdHandle(int nStdHandle);

    [DllImport("kernel32.dll")]
    static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

    [DllImport("kernel32.dll")]
    static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

    static void Main()
    {
        var handle = GetStdHandle(STD_OUTPUT_HANDLE);
        uint mode;
        GetConsoleMode(handle, out mode);
        mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
        SetConsoleMode(handle, mode);

        const string UNDERLINE = "\x1B[4m";
        const string RESET = "\x1B[0m";
        Console.WriteLine("Some " + UNDERLINE + "underlined" + RESET + " text");
    }
}

Console with underlined text

Fayola answered 28/3, 2017 at 19:52 Comment(5)
Sorry, did not work for me.. Have i missed something ?Beaufert
Edit Works, the problem was that i've changed the consts to hexa, hold habits ! Thanks :)Beaufert
Do you know where I can find all the other formatting features besides underline?Riker
Inelegant answer. Being a .NET question, the solution should not be OS dependent, even if it is implied to be .NET Framework.Incorporable
I do not think it is possible to solve this problem in an OS-independent way. Terminals in some OS (e.g. earlier versions of Windows) simply do not have the capability to process ANSI codes. The console in Windows 10 supports them, but this capability can be enabled and disabled in an OS-specific way. en.wikipedia.org/wiki/ANSI_escape_code#DOS,_OS/2,_and_WindowsFayola
L
9

I use this code. It's a fixed version of Vladimir Reshetnikov's answer, using the correct escape code for the reset.

    private static void WriteUnderline(string s)
    {
        var handle = GetStdHandle(STD_OUTPUT_HANDLE);
        uint mode;
        GetConsoleMode(handle, out mode);
        mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
        SetConsoleMode(handle, mode);
        Console.WriteLine($"\x1B[4m{s}\x1B[24m");
    }

This will do underlined text, and has the benefit of not resetting any colors you have set.

Lit answered 1/9, 2018 at 11:21 Comment(0)
R
7

The Windows console does not support ANSI escape sequences. To my knowledge, the only way to change the attributes of an output character is to call SetConsoleTextAttribute before writing the character. Or, in .NET, modify the Console.ForegroundColor or Console.BackgroundColor attributes.

It might be possible to set those properties to custom values (i.e. values not defined by ConsoleColor) with a type cast. But I don't know what good that would do you.

I don't know that I've ever seen strikethrough text on a Windows console, and it's been years since I saw underline. I suppose it's possible, but I don't know how it's done.

Runin answered 8/3, 2011 at 20:29 Comment(1)
Now with Microsoft Windows [Version 10.0.19044.2728] it does see https://mcmap.net/q/219845/-ansi-colors-and-writing-directly-to-console-output-c for example.Motch
C
6

Short answer, no; the console doesn't allow the use of underlined characters in output.

Longer answer: The screen buffer used by the console is little more than a byte array. Each cursor position is one byte or one character. To create an underline, you either need two characters overlapping (which isn't possible in the console), or you need access to a codepage that uses the upper 128 character values as underlined or strikethrough versions of the lower 128 (I don't know of one).

You can work around this if you are willing to go "double-spaced" for lines that have underlines. Character code 0x00AF (decimal 175) is a "text art" character representing a border across the top of the character space. If you use those in the line underneath your text, presto, underlines.

Callant answered 8/3, 2011 at 20:27 Comment(0)
A
4

I found this question and thought I would add to the answers for pre-windows 10 terminal using kernel32 functions,

using System;
using System.Runtime.InteropServices;

namespace color_console
{
    class Class1
    {
        static void Main(string[] args)
        {
            Class1 c = new Class1();
            c.change();
        }

        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool SetConsoleTextAttribute(IntPtr hConsoleOutput, CharacterAttributes wAttributes);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetStdHandle(int nStdHandle);

        [DllImport("kernel32.dll")]
        public static extern bool GetConsoleScreenBufferInfo(IntPtr hConsoleOutput,
                ref CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);


        void change()
        {
            const int STD_OUTPUT_HANDLE = -11;
            IntPtr hOut;
            hOut = GetStdHandle(STD_OUTPUT_HANDLE);

            CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo = new CONSOLE_SCREEN_BUFFER_INFO();
            GetConsoleScreenBufferInfo(hOut, ref ConsoleInfo);
            CharacterAttributes originalAttributes = (CharacterAttributes)ConsoleInfo.wAttributes;

            //write some text
            SetConsoleTextAttribute(hOut, CharacterAttributes.FOREGROUND_BLUE);
            Console.WriteLine("Blue text");

            SetConsoleTextAttribute(hOut, CharacterAttributes.BACKGROUND_RED);
            Console.WriteLine("Red background");

            SetConsoleTextAttribute(hOut, CharacterAttributes.BACKGROUND_GREEN);
            Console.WriteLine("Green background");

            SetConsoleTextAttribute(hOut, CharacterAttributes.BACKGROUND_GREEN | CharacterAttributes.BACKGROUND_RED);
            Console.WriteLine("Yellow background");

            SetConsoleTextAttribute(hOut, CharacterAttributes.FOREGROUND_RED | CharacterAttributes.COMMON_LVB_UNDERSCORE);
            Console.WriteLine("Red underlined text");

            SetConsoleTextAttribute(hOut, CharacterAttributes.FOREGROUND_RED
                                   | CharacterAttributes.FOREGROUND_BLUE);
            Console.WriteLine("Purple text");

            SetConsoleTextAttribute(hOut, CharacterAttributes.FOREGROUND_RED
                                    | CharacterAttributes.FOREGROUND_BLUE
                                    | CharacterAttributes.FOREGROUND_INTENSITY);
            Console.WriteLine("Purple text intense");
           
            SetConsoleTextAttribute(hOut, CharacterAttributes.FOREGROUND_GREEN
                                    | CharacterAttributes.FOREGROUND_BLUE
                                    | CharacterAttributes.COMMON_LVB_REVERSE_VIDEO);
            Console.WriteLine("Aqua reversed text ");

            SetConsoleTextAttribute(hOut, CharacterAttributes.FOREGROUND_GREEN
                                    | CharacterAttributes.FOREGROUND_BLUE
                                    | CharacterAttributes.COMMON_LVB_REVERSE_VIDEO
                                    | CharacterAttributes.FOREGROUND_INTENSITY);
            Console.WriteLine("Aqua reversed intense text ");

            SetConsoleTextAttribute(hOut, CharacterAttributes.COMMON_LVB_GRID_LVERTICAL
                                    | CharacterAttributes.FOREGROUND_GREEN);
            Console.WriteLine("What does this do");

            SetConsoleTextAttribute(hOut, originalAttributes);
            Console.WriteLine("Back to the shire");
        }

        public enum CharacterAttributes
        {
            FOREGROUND_BLUE =   0x0001,
            FOREGROUND_GREEN =  0x0002,
            FOREGROUND_RED =    0x0004,
            FOREGROUND_INTENSITY = 0x0008,
            BACKGROUND_BLUE = 0x0010,
            BACKGROUND_GREEN = 0x0020,
            BACKGROUND_RED = 0x0040,
            BACKGROUND_INTENSITY = 0x0080,
            COMMON_LVB_LEADING_BYTE = 0x0100,
            COMMON_LVB_TRAILING_BYTE = 0x0200,
            COMMON_LVB_GRID_HORIZONTAL = 0x0400,
            COMMON_LVB_GRID_LVERTICAL = 0x0800,
            COMMON_LVB_GRID_RVERTICAL = 0x1000,
            COMMON_LVB_REVERSE_VIDEO = 0x4000,
            COMMON_LVB_UNDERSCORE = 0x8000
        }

 

        [StructLayout(LayoutKind.Sequential)]
        public struct CONSOLE_SCREEN_BUFFER_INFO
        {
            public COORD dwSize;
            public COORD dwCursorPosition;
            public int wAttributes;
            public SMALL_RECT srWindow;
            public COORD dwMaximumWindowSize;
        }

 

        // Standard structures used for interop with kernel32
        [StructLayout(LayoutKind.Sequential)]
        public struct COORD
        {
            public short x;
            public short y;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SMALL_RECT

        {
            public short Left;
            public short Top;
            public short Right;
            public short Bottom;
        }
    }
}

Output on my PC

enter image description here

Alan answered 27/1, 2022 at 17:42 Comment(0)
L
1

It's pretty easy to change the foreground/background color of console : http://www.dotnetperls.com/console-color but AFAIK there is no way to put some bold text, for example. But I didn't really tried to achieve that so i'm not sure.

Lily answered 8/3, 2011 at 20:26 Comment(2)
FYI: What the ConsoleColor calls White is actually "bold gray" as far as how it's translated to Windows API calls. Basically, the 8 "bright" colors are the "dark" colors with FOREGROUND_INTENSITY or BACKGROUND_INTENSITY bit set. See msdn.microsoft.com/en-us/library/…Runin
No you can do Bold using \x1B[1m see more here https://mcmap.net/q/219845/-ansi-colors-and-writing-directly-to-console-output-cMotch

© 2022 - 2024 — McMap. All rights reserved.