The following forum(s) have migrated to Microsoft Q&A (Preview): Developing Universal Windows apps!
Visit Microsoft Q&A (Preview) to post new questions.

Learn More

 locked
[UWP][C#] Xbox controller and KeyDown Event? RRS feed

  • Question

  • This is probably a simple question, but...

    Trying to get my app to respond to buttons pressed on a Xbox (360/One) controller in a way other than the default.  This is my current code:

            private void Page_KeyDown(object sender, KeyRoutedEventArgs e)
            {
                switch (e.Key)
                {
                    case Windows.System.VirtualKey.Space:
                    case Windows.System.VirtualKey.Enter:
                    case Windows.System.VirtualKey.GamepadA:
                        // Do stuff
                        e.Handled = true;
                        break;
                    case Windows.System.VirtualKey.Escape:
                    case Windows.System.VirtualKey.GamepadB:
                    case Windows.System.VirtualKey.GamepadMenu:
                        // Do stuff
                        e.Handled = true;
                        break;
                    case Windows.System.VirtualKey.GamepadLeftShoulder:
                        // Do stuff
                        e.Handled = true;
                        break;
                    case Windows.System.VirtualKey.GamepadY:
                        // Do stuff
                        e.Handled = true;
                        break;                    
                }
            }
    

    The issue I'm having is KeyDown never fires for the A button on the gamepad (and will fire the Click event on the currently active control).  (It does fire for the B button, but as VirtualKey.Escape -- which I can handle).  Other buttons work fine.  Is there a way I can have the actual gamepad button pressed passed to KeyDown (for A and B)?  (Note: I'm making no changes to PointerMode in the code right now -- so it's using the default)

    Monday, October 10, 2016 5:32 PM

Answers

  • There's two things going on here. First, you'll never get a XAML KeyDown with e.Key == GamepadA/B/left/right/up/down -- they are all translated into their nearest keyboard equivalent. Instead, you can use the e.OriginalKey property to get the gamepad key before it's been translated into the keyboard equivalent.

    The second issue is that a lot of controls handle Space and GamepadA -- and an event listener on the page is going to hear about that after the control with focus. If the control did something with the key, it will set e.Handled = true, and subsequent event listeners will not be notified, unless they were hooked up using the AddHandler() method with the "tell me about handled events also" flag.

    So if you're okay with control doing its thing and then the Page hearing about it, use AddHandler instead of += to register your event handler. If you don't want the control to hear about the input at all, you need either subclass that control and override KeyDown/Up, or not let that control have focus.

    Friday, October 14, 2016 5:01 PM

All replies

  • How about just directly using Windows.Gaming.Input to read the gamepad?

    Tuesday, October 11, 2016 4:52 PM
  • How about just directly using Windows.Gaming.Input to read the gamepad?


    That's actually how it works in the current version of the app (pre-anniversary update), however on machines with the Anniversary update installed it will actually read the input from Windows.Gaming.Input and execute the Click event (which can lead to strange things happening).

    In this case I'm using the A button as a "Start / Stop" button on my timer.  If I use Windows.Gaming.Input, it will fire the "Click" action on whichever button is selected using the "default" controller actions, then fire my "Start/Stop" action as well.  By default, the selected button is the "Start / Stop" button, so it will immediately start the timer, then stop it again.

    (Forgot to mention, the app is an XAML app)
    Tuesday, October 11, 2016 5:27 PM
  • There's two things going on here. First, you'll never get a XAML KeyDown with e.Key == GamepadA/B/left/right/up/down -- they are all translated into their nearest keyboard equivalent. Instead, you can use the e.OriginalKey property to get the gamepad key before it's been translated into the keyboard equivalent.

    The second issue is that a lot of controls handle Space and GamepadA -- and an event listener on the page is going to hear about that after the control with focus. If the control did something with the key, it will set e.Handled = true, and subsequent event listeners will not be notified, unless they were hooked up using the AddHandler() method with the "tell me about handled events also" flag.

    So if you're okay with control doing its thing and then the Page hearing about it, use AddHandler instead of += to register your event handler. If you don't want the control to hear about the input at all, you need either subclass that control and override KeyDown/Up, or not let that control have focus.

    Friday, October 14, 2016 5:01 PM
  • Hey Nick,

    I'm trying to capture the A button when the User clicks it while focused on a ListViewItem.  This event gets swallowed, of course, by the ListView or the ListViewItem (I don't know which).

    So, I took your advice and, in the constructor of the UserControl that contains the ListView, I added the following code:

                    AddHandler(UserControl.KeyDownEvent, new RoutedEventHandler((s, e) => {
                        var args = e as KeyRoutedEventArgs;
                    }), true);
    

    This throws an exception with the message "Value does not fall within the expected range.  I've tried many variants of this one line of code including moving it into the UserControl's Loaded event, using UIElement.KeyDownEvent, using this.AddHandler.  They all fail.

    I know this is something I'm doing wrong but I just can't seem to figure out what that is.....

    Your help would be greatly appreciate.....

    Wednesday, December 21, 2016 2:04 AM