4

I am writing this program that I want to run forever via a while loop and whenever the user presses a certain key on their keyboard it exits the program. I've looked everywhere but I have only seen KeyEvents, but the WindowsForm isn't active while the program is running. Anyone have a solution for me?

Edit: The program takes over the cursor so activating an event on the UI is basically impossible

Edit Two:

    public void MainMethod() 
    {
        while (true) 
        {
            if (checkBox1.Checked == true) state = State.PERFORM_ACTION_ONE;
            if (checkBox2.Checked == true) state = State.PERFORM_ACTION_TWO;
            // More stuff checking which state to assign

            switch (state) 
            {

            case State.PERFORM_ACTION_ONE:
                 DoSomething();
                 break;
            // More cases
            // I want it to be able to break anywhere in the while loop
            }
        }
    }
Ipwnusck
  • 63
  • 1
  • 10
  • Are you talking about handling [Ctrl+C in console application](http://stackoverflow.com/questions/19758741/catching-ctrlc-event-in-console-application-multi-threaded) ? – Alexei Levenkov Dec 24 '13 at 23:35
  • There is no threading question here or anything else. He asks "How to close my application using the keyboard while it is not in focus?" That's it. The `while loop` isn't relevant at all. And for his question the answer is HotKeys. – Rudy Dec 24 '13 at 23:40
  • @Rudy - I see... I did read the question totally differently (probably because infinite `while` does not really makes sense to me in WinForm application, and maybe due to lack of WinForms tag)... Now it feels more like [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) - maybe if OP explains what the actual goal is we can find less painful solution than global hooks. – Alexei Levenkov Dec 24 '13 at 23:54
  • WHat type of application are you writing? Service? Console? WinForm? – Black Frog Dec 24 '13 at 23:57
  • You cannot run that tight loop on the UI thread. You have to run your loop on a background thread. – Black Frog Dec 25 '13 at 20:53

4 Answers4

2

You need to set a HotKey like here Set global hotkeys using C# then using that HotKey to exit the application.

Community
  • 1
  • 1
Rudy
  • 2,323
  • 1
  • 21
  • 23
  • This doesn't work, it keeps saying that I can't use the ModifierKeys enum as an instance reference, qualify it as a type name instead (IDK how to do that) – Ipwnusck Dec 25 '13 at 00:01
  • @Ipwnusck, you need to add code to your question. We cannot help you if we don't see what you wrote. – Black Frog Dec 25 '13 at 00:15
  • @BlackFrog I wrote the code exactly how it was in the following question, it didn't work. – Ipwnusck Dec 25 '13 at 00:31
1

You need to run your infinite loop in a separate thread from the UI thread. And have a infinite loop to check on the variable that can be set from UI thread:

while (keepRunning){
  // do stuff
}

and then set event on a button press to change keepRunning to false.

Here is the quick sample:

public partial class Form1 : Form
{
    public static bool KeepRunning;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        KeepRunning = true;
        Task.Factory.StartNew(() =>
                              {
                                  while (KeepRunning)
                                  {
                                      Trace.WriteLine("Keep running");
                                  }
                              });
    }

    private void button2_Click(object sender, EventArgs e)
    {
        KeepRunning = false;
        Trace.WriteLine("Finished Execution");
    }
}
trailmax
  • 34,305
  • 22
  • 140
  • 234
  • 2
    Note that you need either `volatile` or some other form of synchronization. – Ben Voigt Dec 24 '13 at 23:30
  • Yep, absolutely. However, if only one thread writes, other reads, OP can get away without going into depths of multi-threading. – trailmax Dec 24 '13 at 23:32
  • Synchronization is still needed, otherwise the worker thread might never see the updated value. – Ben Voigt Dec 24 '13 at 23:33
  • Not unless you declare `KeepRunning` as static. See code updated sample. – trailmax Dec 24 '13 at 23:42
  • How about this "whenever the user presses a certain key on their keyboard it exits the program" and this "the WindowsForm isn't active while the program is running" ? – Rudy Dec 24 '13 at 23:45
  • @Rudy For that I'm not clear what "WindowsForm isn't active" means. I presume the loop happens in the UI thread, hence the UI is not responsive. If the focus have been taken away from the application, the question should be asked without mentioning the loop, but rather for hotkeys. And your answer will work just fine for that scenario. – trailmax Dec 24 '13 at 23:50
  • @trailmax The user will have trouble or not to be able at all access the WinForm while the program is running – Ipwnusck Dec 25 '13 at 00:03
  • @Ipwnusck that is why you put that loop into a separate thread (Task). Your UI will still active, and the loop is running. The code I provided is working example - I quickly created a sample and confirmed it works: one button starts the loop, another stops the loop. No problem accessing UI. Just try it. – trailmax Dec 25 '13 at 00:06
  • @trailmax I literally mean that while the program is running the user will have trouble accessing the WinForm. It takes over the cursor in order to perform certain actions if the user doesn't realize something. – Ipwnusck Dec 25 '13 at 00:10
  • @Ipwnusck Oh, I see. You should've placed that in the question - that makes the problem and solution completely different. – trailmax Dec 25 '13 at 00:12
0

if you start the loop in another thread you could cancel that thread that it is running when you hit the "hot key" or whatever you want to stop it. Check out BackgroundWorker.

DROP TABLE users
  • 1,955
  • 14
  • 26
  • I was thinking of using separate threads once I found out a solution to hotkey, one thread running while loop another thread actively searching if the hotkey is pressed. – Ipwnusck Dec 25 '13 at 00:12
0

Put the loop into a separate Task.

WinForms will continue to run concurrently on the UI thread, so it can continue to receive the user input. When user requests you to stop, you can use the task cancellation mechanism1 to exit from the loop and the task itself.


1 See the "Canceling a Task" section here.

Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
  • How will the user request the program to stop without accessing WinForm? – Ipwnusck Dec 25 '13 at 00:12
  • @Ipwnusck What do you mean "without accessing Winforms"? The whole idea is to allow WinForms to continue to process user input even while your "infinite loop" is running. – Branko Dimitrijevic Dec 25 '13 at 00:15
  • @Ipwnusck You said you have a while loop that runs forever. Such a loop would block the UI thread and prevent it from processing any user input. My answer is a solution to that. If you have a _different_ question, please clarify. – Branko Dimitrijevic Dec 25 '13 at 00:19
  • Well my question was is there anyway the WinForm application can exit if the user types a certain key on their keyboard while the WinForm is not focused – Ipwnusck Dec 25 '13 at 00:26
  • 1
    @Ipwnusck OK, then you should have said so ;) You'll have to register a global hotkey for that. You'll have to P/Invoke Win32 API (something like [this](http://www.dreamincode.net/forums/topic/180436-global-hotkeys/)) - I don't think there is a convenient .NET wrapper for that. – Branko Dimitrijevic Dec 25 '13 at 02:02