Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Windows Terminal] Console.KeyAvailable causes the next Unicode character input 'EN DASH' to be skipped in console #38966

Open
daxian-dbw opened this issue Jul 8, 2020 · 12 comments
Labels
area-System.Console help wanted [up-for-grabs] Good issue for external contributors
Milestone

Comments

@daxian-dbw
Copy link
Contributor

daxian-dbw commented Jul 8, 2020

Description

When pasting text with Unicode character in it to console on Windows (conhost) using right click, the Unicode character, such as the 'EN DASH' character in the following example

New-StoragePool –FriendlyName

will somehow be skipped and missing from the Console.ReadKey(true) calls. More investigation shows the call to Console.KeyAvailable could be the culprit -- when Console.KeyAvailable is not in use, Console.ReadKey(true) is able to receive the 'EN DASH' character just fine.

Repro code

using System;

namespace console
{
    public class Program
    {
        static void Main(string[] args)
        {
            do {
                if (Console.KeyAvailable)
                {
                    var key = Console.ReadKey(true);
                    Print(key);
                }
                else
                {
                    var key = Console.ReadKey(true);
                    Print(key);
                }
            }
            while(true);
        }

        // Print the decimal value of `KeyChar`, the `ConsoleKey` and `Modifiers` values.
        private static void Print(ConsoleKeyInfo key)
        {
            Console.Write('[');
            Console.Write((int)key.KeyChar);
            Console.Write($" {key.Key} {key.Modifiers}");
            Console.Write(']');
        }
    }
}

Copy the text "l –F", and then right click to paste the text, you will see that the 'EN DASH' character is missing:

image

Then, copy the text "–F" with the 'EN DASH' character being the first character, so Console.KeyAvailable will not run before accepting that character, then Console.Readkey(true) is able to receive that Unicode character ():

image

Additional information

Please note that, the same issue happens in .NET 5 preview as well.

If I change the Main method above to be the following, then Console.Readkey can always receive the Unicode character.
But I have to use Console.KeyAvailable in my project together with Console.ReadKey, and hence cannot receive the Unicode when user is pasting by right click in console.

        static void Main(string[] args)
        {
            do
            {
                var key = Console.ReadKey(true);
                Print(key);
            }
            while(true);
        }
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Console untriaged New issue has not been triaged by the area owner labels Jul 8, 2020
@ghost
Copy link

ghost commented Jul 8, 2020

Tagging subscribers to this area: @eiriktsarpalis
Notify danmosemsft if you want to be subscribed.

@eiriktsarpalis
Copy link
Member

Hi @daxian-dbw

I tried your reproduction locally, but couldn't reproduce the issue. This is what I get on the powershell terminal:
image

And this is what I see using powershell core on Windows terminal:

image

This is using .NET Core 3.1.302, but the behaviour is similar in .NET 5 preview.

@eiriktsarpalis eiriktsarpalis added needs more info and removed untriaged New issue has not been triaged by the area owner labels Jul 20, 2020
@daxian-dbw
Copy link
Contributor Author

daxian-dbw commented Jul 21, 2020

@eiriktsarpalis Thanks for looking into this!
Please try out the repro from cmd.exe. I don't know why it works in PowerShell, but it repros consistently when running it from cmd.exe. Below is a screen gif of it when I paste "l –F" with right clicking. The input/output encoding's are the defaults:

OutputEncoding: utf-8
InputEncoding: Codepage - 437

tabcom

@eiriktsarpalis
Copy link
Member

eiriktsarpalis commented Jul 22, 2020

I'm still not reproducing :/

image

@daxian-dbw are you able to reproduce on a second machine?
@adamsitnik when you get back, would you be able to try and reproduce locally?

@daxian-dbw
Copy link
Contributor Author

@eiriktsarpalis I found the OutputEncoding may plays a role here. I added Console.OutputEncoding = Encoding.UTF8 below to the original repro code, and now I can reproduce the issue in both cmd.exe and powershell core.

using System;
using System.Text;

namespace console
{
    public class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;
            Console.WriteLine("OutputEncoding: {0}", Console.OutputEncoding.WebName);
            Console.WriteLine("InputEncoding: {0}", Console.InputEncoding.WebName);

            do {
                if (Console.KeyAvailable)
                {
                    var key = Console.ReadKey(true);
                    Print(key);
                }
                else
                {
                    var key = Console.ReadKey(true);
                    Print(key);
                }
            }
            while(true);
        }

        private static void Print(ConsoleKeyInfo key)
        {
            Console.Write('[');
            Console.Write((int)key.KeyChar);
            Console.Write($" {key.Key} {key.Modifiers}");
            Console.Write(']');
        }
    }
}

Run from cmd.exe

paste "l –F" by right clicking:

tabcom

paste "–F" with the 'EN DASH' character being the first character by right clicking:

tabcom

Run from powershell core

paste "l –F" by right clicking:

tabcom

paste "–F" with the 'EN DASH' character being the first character by right clicking:

tabcom

@daxian-dbw
Copy link
Contributor Author

daxian-dbw commented Jul 22, 2020

@eiriktsarpalis Additional data point: I found this only reproduce in Windows Terminal. If I do the same in the conhost, then the 'EN DASH' character can always be captured as [45 OemMinus 0], no matter launching console.exe from cmd.exe, or PowerShell core, or Windows PowerShell. Also, I tried on a second machine and it's the same behavior.

So a side question: why the 'EN DASH' character results in different ConsoleKeyInfo in Windows Terminal vs. conhost?

@eiriktsarpalis
Copy link
Member

I'm reproducing the same behaviour. Basically the character is omitted on Windows terminal only (reproducing with either cmd, PowerShell or Git Bash), but not on any other terminal emulators that I tested. It namely works for Visual Studio Console, Git bash, Powershell classic and ConEmu. I'll update the issue description accordingly.

@eiriktsarpalis eiriktsarpalis changed the title Console.KeyAvailable causes the next Unicode character input 'EN DASH' to be skipped in console [Windows Terminal] Console.KeyAvailable causes the next Unicode character input 'EN DASH' to be skipped in console Jul 23, 2020
@eiriktsarpalis
Copy link
Member

Also, the issue does not reproduce when using Windows terminal on WSL.

@eiriktsarpalis eiriktsarpalis added this to the Future milestone Jul 23, 2020
@daxian-dbw
Copy link
Contributor Author

It would be very helpful if @DHowett can share some insight, especially on this question:

So a side question: why the 'EN DASH' character results in different ConsoleKeyInfo in Windows Terminal vs. conhost?

Thanks in advance @DHowett!

@msftrncs
Copy link

msftrncs commented Feb 3, 2021

This looks like a potential problem area.

// Skip non key-down && mod key events.
if (!IsKeyDownEvent(ir) || IsModKey(ir))
{
r = Interop.Kernel32.ReadConsoleInput(InputHandle, out ir, 1, out numEventsRead);
if (!r)
throw Win32Marshal.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
}
else
{
return true;
}

Could it be possible that these characters are not triggering IsKeyDownEvent and this loop is eating them?

@shibayan
Copy link

shibayan commented Aug 7, 2021

I've noticed the same problem. Similarly, if you call Console.KeyAvailable, certain characters will be skipped. This occurred when I pasted a string containing 'KATAKANA MIDDLE DOT' into the console as shown below.

A・B

Oddly enough, it didn't happen in the Windows Terminal, but seemed to happen in the command prompt.

Repro code

using System;

namespace ConsoleApp28
{
    class Program
    {
        static void Main(string[] args)
        {
            do
            {
                var keyInfo = Console.ReadKey(true);

                Console.WriteLine($"KeyChar = {keyInfo.KeyChar}, Key = {keyInfo.Key}, Modifiers = {keyInfo.Modifiers}");

            } while (Console.KeyAvailable/*true*/);
        }
    }
}

Use Console.KeyAvailable

paste "A・B" by right clicking:

image

Not use

paste "A・B" by right clicking:

image

@adamsitnik
Copy link
Member

adamsitnik commented Nov 14, 2023

This looks like a potential problem area.

I've marked this issue with help wanted label. The person who is willing to work on it should take one of the provided repro apps and debug the code pointed by @msftrncs in #38966 (comment) If that is the source of the problem, please send a PR with a fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Console help wanted [up-for-grabs] Good issue for external contributors
Projects
None yet
Development

No branches or pull requests

7 participants
@daxian-dbw @shibayan @eiriktsarpalis @adamsitnik @msftrncs @Dotnet-GitSync-Bot and others