Asked  7 Months ago    Answers:  5   Viewed   92 times

How can I continue to run my console application until a key press (like Esc is pressed?)

I'm assuming its wrapped around a while loop. I don't like ReadKey as it blocks operation and asks for a key, rather than just continue and listen for the key press.

How can this be done?

 Answers

56

Use Console.KeyAvailable so that you only call ReadKey when you know it won't block:

Console.WriteLine("Press ESC to stop");
do {
    while (! Console.KeyAvailable) {
        // Do something
   }       
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
Tuesday, June 1, 2021
 
Zach
answered 7 Months ago
87

What @Frank Krueger said. Do you really want to do this? Windows Forms is designed to make this much easier.

If you do, you'll need to use PInvoke into the low level Windows API. Try this as a starting point - but be aware that this is considerably more complex than the Windows Forms application would be.

Thursday, June 10, 2021
 
Viralk
answered 6 Months ago
74

You can use P/Invocation to be able to use WinAPI's GetAsyncKeyState() function, then check that in a timer.

<DllImport("user32.dll")> _
Public Shared Function GetAsyncKeyState(ByVal vKey As System.Windows.Forms.Keys) As Short
End Function

Const KeyDownBit As Integer = &H8000

Private Sub Timer1_Tick(sender As Object, e As System.EventArgs) Handles Timer1.Tick
    If (GetAsyncKeyState(Keys.LWin) And KeyDownBit) = KeyDownBit AndAlso (GetAsyncKeyState(Keys.O) And KeyDownBit) = KeyDownBit Then
        'Do whatever you want when 'Mod + O' is held down.
    End If
End Sub

EDIT:

To make the code only execute one time per key press, you can add a little While-loop to run until either of the buttons are released (add it inside your If-statement):

While GetAsyncKeyState(Keys.LWin) AndAlso GetAsyncKeyState(Keys.O)
End While

This will stop your code from executing more than once while you hold the keys down.

When using this in a Console Application just replace every System.Windows.Forms.Keys and Keys with ConsoleKey, and replace LWin with LeftWindows.

Sunday, June 20, 2021
 
employeegts
answered 6 Months ago
13

The Progress<T> class uses the current synchronization context for the thread in which it was created to invoke the event handlers for its ProgressChanged event.

In a console application, the default synchronization context uses the thread pool to invoke delegates, rather than marshaling them back to the thread where the context is retrieved. This means that each time you update progress, the event handler may be invoked in a different thread (especially if the progress updates occur in quick succession).

Due to the way threads are scheduled, there is no guarantee that a thread pool worker assigned a task before another thread pool worker will actually run its task before that other worker runs its task. Especially for relatively simple tasks (such as emitting progress messages), it can easily be the case then that tasks enqueued later are actually completed before tasks enqueued earlier.

If you want for your progress update messages to be guaranteed to be displayed in order, you'll need to use a different mechanism. For example, you could set up a producer/consumer with BlockingCollection<T>, where you have a single thread consuming messages that are queued (produced) by your operations that report progress. Or, of course, you could just call Console.WriteLine() directly (as you have already verified will work).

Note that that doesn't mean you need to abandon the idea of using IProgress<T>. It just means you would need to provide your own implementation, rather than using the Progress<T> class, at least in the console scenario. For example:

class ConsoleProgress : IProgress<string>
{
    public void ReportProgress(string text)
    {
        Console.WriteLine(text);
    }
}

This would allow you to, for example, keep the IProgress<T> abstraction in the IdRecounter() class, decoupling that type from the UI context. It could be reused for a console program as well as any GUI API program, such as Winforms, WPF, Winrt, etc.


The bottom line: Progress<T> is a very useful implementation of IProgress<T> when you need to abstract the cross-thread, synchronization context-related operations that are needed in a GUI program. It will work in console programs, but because it will use the thread pool in that case, you may not get deterministically ordered output, at least not without including additional synchronization to the ProgressChanged event handlers.

Wednesday, August 4, 2021
 
Matt Bullock
answered 4 Months ago
23

If you capture the ConsoleKeyInfo, you will get additional information, including the Modifiers keys. You can query this to see if the Control key was pressed:

ConsoleKey key;

do
{
    while (!Console.KeyAvailable)
    {
        // Do something, but don't read key here
    }

    // Key is available - read it
    var keyInfo = Console.ReadKey(true);
    key = keyInfo.Key;

    if ((keyInfo.Modifiers & ConsoleModifiers.Control) != 0)
    {
        Console.Write("Ctrl + ");
    }
    if (key == ConsoleKey.NumPad1)
    {                    
        Console.WriteLine(ConsoleKey.NumPad1.ToString());
    }
    else if (key == ConsoleKey.NumPad2)
    {
        Console.WriteLine(ConsoleKey.NumPad2.ToString());
    }

} while (key != ConsoleKey.Escape);
Wednesday, September 1, 2021
 
Asperi
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share