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

SIGINT (Exiting RootWindow's Run Method) #8

Closed
thecliguy opened this issue May 29, 2018 · 16 comments
Closed

SIGINT (Exiting RootWindow's Run Method) #8

thecliguy opened this issue May 29, 2018 · 16 comments

Comments

@thecliguy
Copy link

Conventionally, console applications respond to CTRL+C as a SIGINT signal and not as keyboard input.

SIGINT can be intercepted by an application so that it can perform a clean exit.

Windows doesn't have many examples of interactive console applications, but one example is the text editor Vim. Upon intercepting a SIGINT Vim prompts the user to exit the program by using its quit syntax:
image

On Linux, there are many examples of console applications which respond to SIGINT, such as:

  • htop (interactive process viewer)
  • Mutt (email client)
  • Lynx (text web browser)
  • GoAccess (web log analyzer)

Ideally NSCI would give the programmer the option to simply ignore SIGINT or to take some action.

@LokiMidgard
Copy link
Owner

I have added an options parameter to the RootWindow constructor that controls this.

@thecliguy
Copy link
Author

@LokiMidgard Using the latest commit, I get the following error on the Run method of RootWindow:

Exception calling "Run" with "0" argument(s): "This property has already been set and cannot be modified."

@LokiMidgard
Copy link
Owner

I've added this line

System.Threading.Thread.CurrentThread.Name = "UI Thread";

In my tests this runs without problems, are you setting a Thread name somewhere explicit?

@LokiMidgard LokiMidgard reopened this Jun 24, 2018
@thecliguy
Copy link
Author

thecliguy commented Jun 24, 2018

No, I am not setting a thread name.

Here is a PowerShell example which simply creates an empty grid:

$NDPropertyDll = "C:\Users\thecliguy\.nuget\packages\ndproperty.core\0.13.12\lib\netstandard1.3\NDProperty.Core.dll"
Add-Type -Path $NDPropertyDll -PassThru

$NitoDisposablesDll = "C:\Users\thecliguy\.nuget\packages\nito.disposables\1.2.1\lib\netstandard1.0\Nito.Disposables.dll"
Add-Type -Path $NitoDisposablesDll -PassThru

$NitoAsyncDll = "C:\Users\thecliguy\.nuget\packages\nito.asyncex.context\5.0.0-pre-03\lib\netstandard1.3\Nito.AsyncEx.Context.dll"
Add-Type -Path $NitoAsyncDll -PassThru

$NitoTasksDll = "C:\Users\thecliguy\.nuget\packages\nito.asyncex.tasks\5.0.0-pre-03\lib\netstandard1.3\Nito.AsyncEx.Tasks.dll"
Add-Type -Path $NitoTasksDll -PassThru

$NsciDLL = "C:\Users\thecliguy\Documents\Scripts\NSCI_Tests\NSCI-master_24-06-18\NSCI-master\NSCI\bin\Debug\netstandard2.0\NSCI.dll"
Add-Type -Path $NsciDLL -PassThru

$Root = [NSCI.UI.RootWindow]::new()
$grid = [NSCI.UI.Controls.Layout.Grid]::new()
$Root.Content = $grid;
$Root.Run()

I have also tried passing NsciOptions to the RootWindow constructor, EG:

$NsciOptions = [NSCI.UI.NsciOptions]::new()
$Root = [NSCI.UI.RootWindow]::new($NsciOptions)

@LokiMidgard
Copy link
Owner

LokiMidgard commented Jun 24, 2018

Hm...
in PowerShell the thread is already named Pipeline Execution Thread. Hope that this does not make more problems.

@thecliguy
Copy link
Author

thecliguy commented Jun 24, 2018

That has fixed the error, but I cannot get ctrl + c to work in PowerShell.

I have implemented the following, but when pressing ctrl + c nothing happens:

$NsciOptions = [NSCI.UI.NsciOptions]::new()
$NsciOptions.TreatControlCAsInput = $False
$Root = [NSCI.UI.RootWindow]::new($NsciOptions)

It works fine for me in C# though:

var NsciOptions = new NSCI.UI.NsciOptions
{
    TreatControlCAsInput = false
};

var root = new NSCI.UI.RootWindow(NsciOptions);

Any ideas? Does it work in PowerShell for you?

@LokiMidgard
Copy link
Owner

Unfrotunatly I have no idea. The CanleKeyPress call back is used, but it does not matter if ConsloeCancelEventArgs.Cancel is false or true. the console application does not stop.

I'm not sure whit the scripting stuff, maybe ctrl-c would terminate the process, but there was no process started. So only the executed function is terminated, but not additional threads that were spawned like UI and input thread. If that would be the case, then you would need to handle OnCancelPressed yourself and call Detach on the RootWindow.

@LokiMidgard
Copy link
Owner

I've noticed wired behavior when the application was terminated via esc input behaves strage after that.

Most likely the input thread was still running. It was actually an endless loop, that was intended to live as long as the process. And when the process was killed it should vanish. But this did not happen in PowerShell.

I no explicitly stop the Thread if the app was stoped like the UI thread before. However The thread is most likely currently blocking in Console.ReadKey() when the app is stoped. And thus the first key pressed after termination will be consumed.

So, for PowerShell you must handle the Ctrl+C command with a Detach yourself.

@thecliguy
Copy link
Author

@LokiMidgard OK, I have handled ctrl + c by assigning a ScriptBlock to OnCancelPressed which calls the Detach method of the RootWindow:

$NsciOptions = [NSCI.UI.NsciOptions]::new()
$NsciOptions.TreatControlCAsInput = $False
$NsciOptions.OnCancelPressed = {$Root.Detach()}
$Root = [NSCI.UI.RootWindow]::new($NsciOptions)

ctrl + c now exits the script but there are two problems...

Problem 1:
After exiting, you must now press a key twice before it is displayed on the console window. EG, if you want to type the letter A, you must press the A key twice.

Problem 2:
When NSCI exits it clears the console buffer. This is not the expected behaviour for a console application. When a console application exits, any output present on the console prior to it starting should be preserved when it exits. Try any console application on Linux and you will see this is the standard behaviour (EG. vim, htop, Mutt, etc).

Possible solution:
There are two types of screen buffer - the Normal Screen Buffer and the Alternate Screen Buffer. This is a standard found in almost all consoles/terminals, so it should work in almost any console on any operating system. When a full screen console application is invoked, it should use the Alternate Screen Buffer. When the application exits the console will return to the Normal Screen Buffer. So NSCI should be using the Alternate Screen Buffer.

Here is some information on the Alternate Screen Buffer:

If NSCI used the Alternate Screen Buffer it should fix problem 2 and it might also fix problem 1.

I can do some more research into implementing Alternate Screen Buffer in a C# application. I would be interested in your thoughts...

@thecliguy
Copy link
Author

@LokiMidgard Your commit to terminate input thread when application stops (48336a4) has fixed problem 1 in my last comment.

LokiMidgard added a commit that referenced this issue Jun 24, 2018
@LokiMidgard
Copy link
Owner

If this would work, it would be nice. But as far as I know the C# Console class is quite limited. I haven't found any method to switch to an alternative screen buffer. Also escape sequences to manipulate the console don't work. (e.g. "\x1b[31mThis text has a red foreground using SGR.31.\r\n")

I have disabled Console.Clear() as you suggested.

@LokiMidgard
Copy link
Owner

@LokiMidgard Your commit to terminate input thread when application stops (48336a4) has fixed problem 1 in my last comment.

I still have this problem for the first charakter I type after termination. Maybe I need to operate on the inputstream directly instead of using the Console.ReadKey() method. I need to check this out another time.

@thecliguy
Copy link
Author

thecliguy commented Jun 24, 2018

Sorry, I don't think the changes in f62db0e are a good idea.

I think its better to revert those changes and implement Alternate Screen Buffer instead.

VT escape sequence support has existed in *nix forever. In Windows, it was introduced into conhost in the Windows 10 Anniversary Update: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences

The reason the VT escape sequence was not working for you is because you have to explicitly enable Virtual Terminal Processing in NSCI for the Windows console.

Please see this example: thecliguy@d21d392, where I have

  • Added support for Virtual Terminal Processing.
  • Enable Alternate Screen Buffer when RootWindow is run.
  • Enable Normal Screen Buffer when RootWindow is exited.

It is not the best code because I am not a C# developer.

There is one problem with the code, colours do not work:
image

@thecliguy
Copy link
Author

thecliguy commented Jun 24, 2018

I forgot to remove the changes from this commit in my code: f62db0e

Its better they are removed.

@LokiMidgard
Copy link
Owner

Up to now I explicitly tried to avoid native code and have a .net only implementation.
I inteded it to run also on Linux and mac. But this extern methods are only used on Windows and Linux should support thos code without any setting.

The next thing that comes in mind is what happens on Systems previor to Windows 10 Anniversary Update.

I still would like to use the alternate screenbuffer, currently I have some problems with the line break of the last char and I hope the alternate screen buffer could prevent this.

By the way, thanks for your implementation. I will look at it in the next days.

@LokiMidgard
Copy link
Owner

If you don't mind we can continue this in #16.

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

2 participants