jaebeom lim
jaebeom lim

Reputation: 11

How to escape while loop using keyboard input in C#

I am using C# in the .Net Framework 8.0. I want to escape while loop using Keyboard input.

At below C# code,

1) If I remove " MessageBox.Show(State.ToString()); ", I can't escape the while loop.

2) If I add "MessageBox.Show(State.ToString());", I can escape the while loop. But, it's not perfect. Because after I see the MessageBox " false ", I must press "A" and Enter. Then Next Step, State is changed to "true". And I can see "true" > " Entered !!! " > "While Loop is Broken !!!" MessageBox.

a) What is the difference 1) and 2).

b) How can I escape while loop using keyboard input? Easily.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Windows.Input;

namespace WF_Templete_
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void bt_Start_Click(object sender, EventArgs e)
        {
            while (true)
            {
                bool State = (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.A) == true);
                // MessageBox.Show(State.ToString());

                if (State)
                {
                    MessageBox.Show("Entered !");
                    break;
                }
            }
            MessageBox.Show("While Loop is Broken !!!");
        }

    }
}

Upvotes: 1

Views: 1411

Answers (2)

Matthew Watson
Matthew Watson

Reputation: 109567

From your comments, it looks like you want to be able to start waiting for an external USB button press, or for a cancellation key on the keyboard to be pressed.

One way to approach this is to encapsulate the waiting for USB button or cancellation in a class like so:

public sealed class UsbButtonWaiter
{
    public UsbButtonWaiter(CancellationToken cancellation)
    {
        _cancellation = cancellation;
    }

    public async Task<bool> WaitForUsbButtonAsync()
    {
        var waitForUsbButton    = Task.Run(this.waitForUsbButton);
        var waitForCancellation = new Task(() => throw new InvalidOperationException(), _cancellation);

        return await Task.WhenAny(waitForUsbButton, waitForCancellation) == waitForUsbButton;
    }

    void waitForUsbButton()  // No idea how your code works for this, so here's a simulation.
    {
        Thread.Sleep(30000); // Simulate it taking 30s for the USB button to be pressed.
    }

    readonly CancellationToken _cancellation;
}

Then you can use a cancellation token to cancel waiting for the USB button press.

As an example of how to use this in a form, here I have created a form with a single button called button1 (the default when you add a new button to a form).

When you press this button, the code will start waiting for a USB button press, or for the user to press the A key on the keyboard. You can test this code by creating a default Windows Forms app and dropping a default button onto the main form (which will be called Form1 by default).

Then add the following code to Form1:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);

        if (_cancellation == null)
            return;

        if (e.KeyCode == Keys.A)
            _cancellation.Cancel();
    }

    async void button1_Click(object sender, EventArgs e)
    {
        if (_cancellation != null) // Already waiting?
            return;

        button1.Enabled = false;
        button1.Text = "Waiting...";

        _cancellation = new CancellationTokenSource();
        UsbButtonWaiter waiter = new UsbButtonWaiter(_cancellation.Token);

        bool wasUsbButtonPressed = await waiter.WaitForUsbButtonAsync();

        if (wasUsbButtonPressed)
            MessageBox.Show("USB button was pressed");
        else
            MessageBox.Show("Cancel key was pressed");

        button1.Enabled = true;
        button1.Text = "button1";
    }

    CancellationTokenSource _cancellation;
}

If you run this application and click button1, its text will change to Waiting..., and it will become disabled.

Then nothing will happen until either you press A or 30s elapses, whereupon a message box will be displayed telling you if the USB button was pressed or the user cancelled, and the button will be re-enabled.

(Note that, of course, the USB button is never really pressed since it is just a simulation, but you can substitute the appropriate code.)

Upvotes: 0

Murray Foxcroft
Murray Foxcroft

Reputation: 13755

The simplest solution is to add in Application.DoEvents() in to the loop. This allows your code to process events that would otherwise be ignored during a tight loop.

Ideally you would want to run your business logic outside of the UI thread using a MVC or MVVM pattern, which would then leave you with a responsive UI that can be interacted with whilst back end processing is performed.

            while (true)
            {
                Application.DoEvents();
                bool State = (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.A) == true);
                // MessageBox.Show(State.ToString());

                if (State)
                {
                    MessageBox.Show("Entered !");
                    break;
                }
            }

Upvotes: 1

Related Questions