Skip to content

Garbage characters get inserted into the input line while pressing left right arrow keys #658

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

Closed
jianyunt opened this issue Mar 31, 2018 · 11 comments

Comments

@jianyunt
Copy link
Contributor

jianyunt commented Mar 31, 2018

By pressing and holding the left or right arrow keys you will see ascii sequence key code (OC, OD) gets inserted into your input string. The issue is reproducible on a Linux native terminal too. But on cloudshell it is easy to repro. The output looks like:

image

Initial Investigation

I am using the 2.0 PSReadline module. To repro it on Linux, I just run Register-EventObject to create a background job - that's what the cloudshell does for Azure token handling. It seems as long as a user has background jobs running, he will likely encounter the issue while pressing and holding Left and Right arrow keys or doing inputs on Linux machine.

  $Timer=New-Object Timers.Timer
  $Timer.Interval = 200
  $Timer.Enabled=$true
  foreach($I in 1..3){$job=Register-ObjectEvent -InputObject $Timer -EventName Elapsed -SourceIdentifier $i -Action {Get-Content /home/myname/pscore/powershell/build.psm1}}

It looks like the PSReadline is handling eventSubscribers. In this case, it found 3 subscribers so entered the code block from line 184 to 231. I am not sure what this code block is trying to archive, but if I comment them out, the issue disappears and all key press seems start working properly.

Environment data

image

Steps to reproduce or exception report

  • Ubuntu 16.04.1 LTS (Xenial Xerus) . Note I did not try on other distro
    or http//portal.azure.com and click on CloudShell

  • pwsh

  • run the above script to register some events if you are trying on your own Linux machine

  • type Hello and press and hold left or right arrow key

@lzybkr
Copy link
Contributor

lzybkr commented Mar 31, 2018

@jianyunt - without that loop, events will not be processed until after accepting input (the user pressed Enter) - this could delay event processing for hours or more, e.g. when the user is away from the computer.

I'm not 100% certain here, but I suspect the event processing is taking too long, and when that happens, the tty decides to print the output because it wasn't consumed. I'd take a look at man stty for some ideas on options that might help.

@daxian-dbw
Copy link
Member

daxian-dbw commented Apr 2, 2018

I think @lzybkr's theory is correct. This can easily repro by replacing the Action with {sleep -milliseconds 500}, which takes too much time to process. After that, pressing any key will result in a ^[O character on the console.

@lzybkr
Copy link
Contributor

lzybkr commented Apr 2, 2018

As I described, the event processing within PSReadLine is necessary to process events in a timely manner, but only because the runspace is busy while PSReadLine because it is called via the PowerShell function PSConsoleHostReadLine.

In my ideal world, the console host wouldn't need to call PSConsoleHostReadLine - it could call the C# api directly. I even tried to implement this in the V5 time frame, but ran into some difficulties with custom keybindings implemented in PowerShell script.

I don't remember the difficulties I hit, but I likely did not have enough time to work through them, I don't recall any fundamental reason why that approach couldn't work.

That said, it might make sense for cloudshell to create a background runspace and process events in that runspace instead of the default runspace.

@jianyunt
Copy link
Contributor Author

jianyunt commented Apr 2, 2018

According to @Tyriar, appending ^[OD is ok while a process is busy. However we are replacing or inserting OD to user's input text. That's the problem. Somehow we lost escape key and treated ^[OD as OD as a user input?

@lzybkr
Copy link
Contributor

lzybkr commented Apr 2, 2018

It's possible Console.ReadKey is not working correctly, but I don't think there is anything in PSReadLine other than the event processing that could address this problem.

@Tyriar
Copy link

Tyriar commented Apr 2, 2018

Here's what I observed when @jianyunt visited on Friday, the terminal emulator is sending the correct sequences to PowerShell and since PS rewrites the prompt whenever input is changed or cursor movement happens, it's a problem with how PS is handling the incoming text stream. Other shells like bash and zsh handle this fine. I don't know enough about PS to know if it's a problem with the core or readline though.

A very easy to repro scenario that's similar to this is to launch a terminal with bash, then run pwsh and hit left arrow several times as it's launching.

@SeeminglyScience
Copy link
Contributor

@lzybkr this may be related to the issue I mentioned in #626. The System.Console implementation for Linux locks on an internal static object while it accesses stdin, including checking properties like Console.CursorLeft and calling Console.ReadKey.

So there is already a pending Console.ReadKey with a lock on stdin , then PSRL checks for events. If it finds any subscribers it checks the cursor position right before invoking the PowerShell instance so it can position the prompt correctly in the case of the subscriber writing to stdout. When the cursor position is checked here the thread blocks until the initial Console.ReadKey releases.

@lzybkr
Copy link
Contributor

lzybkr commented Apr 2, 2018

@Tyriar - PSReadLine 2.0.0-beta1 does not rewrite like it did in 1.2. It only touches the prompt if there is a syntax error or if asked to call the prompt function, e.g. after showing possible completions.

The startup scenario can impact bash as well on a heavily loaded or slow system - one will see ^[0D or whatever before the prompt is responsive. The difference I see is that pwsh doesn't render those characters again - but if you hit enter, I think the command line was captured correctly.

@SeeminglyScience - thanks for chiming in. Maybe it's worth an experiment to remove the code querying the cursor position. If that fixes the problem, I'm still not sure what the best option is, but one option would be to live with the somewhat poor experience if an event handler writes to stdout (which is arguably an unfriendly event handler anyway).

@jianyunt
Copy link
Contributor Author

jianyunt commented Apr 3, 2018

@lzybkr the code is handling escape sequence for Windows. On Linux, InEscapeSequence is always false. How multiple keys work on Linux?

@lzybkr
Copy link
Contributor

lzybkr commented Apr 3, 2018

@jianyunt - the Windows input VT escape processing code is not currently active - you should consider that code work in progress to eventually support running powershell.exe under a program like tmux or screen.

The Linux escape sequence processing is done in the CLR - I think here.

@jianyunt
Copy link
Contributor Author

The root cause seems to be https://github.com/dotnet/corefx/issues/29669.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants