0

I'm writing an application which has multiple states. The states are swapped by pressing space, and current state is stored in an enum. I handle the swapping by KeyUp and KeyDown Event.

I want to achieve: When I press (and hold) the space key, I just wanna swap to the next phase, and wait until the space key is released. When it is released, the window does something (counting time using StopWatch and DispatcherTimer) and that stops after I press the space again, which also swaps to next state and so on.

The window holds properties of the current phasis (Phase) and event methods for the KeyUp and KeyDown events (called KeyRelease() and KeyPress()):

    private enum EPhase { Initiation, Countdown, MeasureTime, End }

    public event PropertyChangedEventHandler PropertyChanged;
    private void UpdateProperty(string name) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 

    private Phase _phase;
    private Phase { get { return _phase; } set { _phase = value; }

    private void KeyPress(object sender, KeyEventArgs e)
    {
        switch (Phase)
        {
            case EPhase.Initiation:
                {
                    if (e.Key == Key.Space)
                    {
                        Phase = EPhase.CountDown;
                        timer.SetCountdown(30);
                    }
                    break;
                }
            case EPhase.CountDown:
                {
                    if (e.Key == Key.Space)
                    {
                        Phase = EPhase.MeasureTime;
                        timer.StopTime();
                        timer.ResetTime();
                    }
                    break;
                }
            case EPhase.MeasureTime:
                {
                    Phase = EPhase.End;
                    timer.StopTime();
                }
            case EPhase.End: break;
        }
        e.Handled = true;
    }

    private void KeyRelease(object sender, KeyEventArgs e)
    {
        switch (Phase)
        {
            case EPhase.Initiation: break;
            case EPhase.Countdown:
                {
                    if (e.Key == Key.Space) timer.Countdown();
                    break;
                }
            case EPhase.MeasureTime:
                {
                    if (e.Key == Key.Space) timer.StartMeasure();
                    break;
                }
            case EPhase.End:
                {
                    if (e.Key == Key.Space) Phase = EPhase.Initiation;
                    break;
                }
        }
        e.Handled = true;
    }

Where The timer is an instance of my Timer class, which is my own class for handling the measurement and counting down. A Property of this class in bind to textblock of the form.

And here's the catch - I'm trying to use the e.Handled = true; to prevent the event firing in a loop while I'm holding the space key, but it doesn't happen, so i just start to hold the space but the Phase keeps looping and so it doesn't work. Anyone has an idea of what I'm doing wrong? How to solve it, please?

Krepsy 3
  • 63
  • 1
  • 2
  • 11
  • `Handled` is a way for your event handler to signal to the caller that _that_ particular event has been handled. It has no effect on subsequent input events. If you only want to handle the initial key-down event, look at the `IsRepeat` property, and do your logic only when that property is `false`. See marked duplicate. – Peter Duniho Mar 31 '17 at 19:15
  • Edited, so please respond, because the other answer helped answering the opposite problem - he wanted to fire only when he is holding (and I even read this question, but I have no idea how to code it). Will someone explain how to do it please? Or maybe explain the IsRepeat and Handled behaviours? I couldn't find the explanation i would undrestand to anywhere... Thank you – Krepsy 3 Mar 31 '17 at 19:24
  • _"he wanted to fire only when he is holding"_ -- seriously? you are unable to generalize the information in the marked duplicate, so that you execute your code only when `IsRepeat` is `false`, instead of only when it is `true`? Besides which, I already explained in my first comment how you should use the property. As for an explanation of the properties, has it occurred to you to look at [the documentation](https://msdn.microsoft.com/en-us/library/system.windows.input.keyeventargs(v=vs.110).aspx)? – Peter Duniho Mar 31 '17 at 19:26
  • Yes, I did look into the documentation ("Or maybe explain the IsRepeat and Handled behaviours? I couldn't find the explanation i would undrestand to anywhere...") but it's not clear to me, how does the WPF trait an key being repeated? I wanted to do it by tracking the IsDown property, but I didn't manage to think up a correct and working way to do it – Krepsy 3 Mar 31 '17 at 19:58
  • _"how does the WPF trait an key being repeated?"_ -- exactly in the way you care about. I.e. Windows generates key-repeat messages if you hold the key down, creating additional key inputs. You want to ignore these. The `IsRepeat` property will be `true` in those events. – Peter Duniho Mar 31 '17 at 20:02
  • Thank you -worked for me nicely. So, the first time the event is passed for one key, the IsRepeat is false, then until release, it stays on true, if the event reffers to same key. – Krepsy 3 Mar 31 '17 at 20:08
  • _"if the event reffers to same key"_ -- more specifically, if the event refers to the same key, while the key is still being held down. If the user presses the key, lets go, and then presses again, you'll get two key-down events, both of which will have `IsRepeat` set to `false`. It's set to `true` only when the _operating system_ is the one that generated the key-down event. – Peter Duniho Mar 31 '17 at 20:10

0 Answers0