Sumel007
Topic Author
Posts: 30
Joined: 19 Mar 2020, 10:50

Changing GamepadAccept to work as Key_Enter instead of Key_Space

15 May 2023, 13:37

Hello!

I have a problem with keyboard/gamepad navigation and I'm not sure how to solve it, I think remapping xbox's A button to enter on the keyboard would fix it.

If I have multiple buttons and I hover over one of them with mouse and then change focus with keyboard and press enter, the new keyboard-focused button's command gets invoked (it generally behaves the same as if I clicked it with mouse). However if I press space (or xbox A) in my project the focus jumps to the button that has mouse cursor over it and the command doesn't get invoked on the keyboard-focused button. I have checked with the Buttons sample of Native SDK (controller wasn't working for the Managed SDK sample) and it seems to behave similarly (ie. space/xbox A changes focus, and enter doesn't), but at least the command gets invoked on the correct button.

I don't know why the command is not invoked in our project (both key pressed and released events are raised in correct order), but I was wondering if there is a way to force keyboard space and xbox button A to work the same way as keyboard enter when it comes to navigation and keyboard focus (other than remapping it on our end before passing it onto Noesis). Since that is what I'd expect as the end user (ie. if I start using keyboard/gamepad the mouse should be ignored and the focus jumping to hovered-over contorl is unexpected) and it would also solve the command not being invoked issue.
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Changing GamepadAccept to work as Key_Enter instead of Key_Space

16 May 2023, 11:37

Hi,

You have to take into account that Buttons sample defines triggers to focus the button when the mouse is over. If you remove those triggers the focus won't change pressing neither Enter nor Space key.

The difference between Space and Enter in a Button is that pressing space also captures mouse, because it allows to raise the click event when the key is released. When the mouse capture is released, it evaluates which element is under the mouse, triggering the MouseEnter event on the hovered element. On the other hand, enter key raises the click on key down and doesn't captures the mouse: https://referencesource.microsoft.com/# ... ase.cs,591

Also consider that not all controls work with the Enter key. For example, a CheckBox by default won't react to the Enter key.
if I start using keyboard/gamepad the mouse should be ignored and the focus jumping to hovered-over contorl is unexpected
As I explained this is not the default behavior, is a consequence of using triggers (MouseEnter) + SetFocusAction.
it would also solve the command not being invoked issue
How is this related? The command is correctly invoked in the button that has focus, right?
 
Sumel007
Topic Author
Posts: 30
Joined: 19 Mar 2020, 10:50

Re: Changing GamepadAccept to work as Key_Enter instead of Key_Space

16 May 2023, 16:08

Thank you for the explanation. We've based our system off of the buttons example, so we were using it along with the SetFocus actions on MouseEnter. I now see where the unexpected behaviors were coming from. I think to solve this I'll just override the button or add a behavior that will handle KeyDown/Up for the buttons and treat space as if enter was pressed. This should let us achieve what we want.
How is this related? The command is correctly invoked in the button that has focus, right?
The command in our project was not being invoked via space (it was via enter though). I now see why, on mouse leave I focus the window, to remove all hover visual effects (since they're based off of focus in our case).
<noesis:StyleTriggerCollection>
                            <b:EventTrigger EventName="MouseEnter">
                                <noesis:SetFocusAction/>
                            </b:EventTrigger>
                            <b:EventTrigger EventName="MouseLeave">
                                <noesis:SetFocusAction TargetObject="{Binding Path=., RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
                            </b:EventTrigger>
                        </noesis:StyleTriggerCollection>
Without the mouse leave logic it works correctly (ie. same as Buttons sample). This is probably expected with the mouse capture logic as you've explained.
I assume my solution of swapping space to enter via a behavior will solve this issue as well.
 
Sumel007
Topic Author
Posts: 30
Joined: 19 Mar 2020, 10:50

Re: Changing GamepadAccept to work as Key_Enter instead of Key_Space

17 May 2023, 13:05

So I've made a behavior that maps space to enter via PreviewKeyDown/PreviewKeyUp events. If the key is space it sets e.Handled to true (so the space event doesn't get propagated) and then it raises KeyDown/KeyUp events with the enter key. It works correctly for keyboard - space behaves the same as enter key now. So I thought the issue was solved. However, for some reason when using Xbox A button it doesn't work. Seemingly nothing happens (the focus doesn't even jump to moused-over button, so the e.Handled must be working, but raising the enter key event seems to do nothing?). I find this very strange, since I thought GamepadAccept gets mapped to space, so it should behave the same as keyboard space key. Via debugging it seems that my PreviewKeyDown/Up events get called with space being the argument when pressing xbox A button, so I don't know why it behaves differently from keyboard space.
Do you have any idea what might be wrong? Is there some internal difference in Noesis when we pass GamepadAccept as opposed to keyboard space key?

Below is my behaviour class.
#if NOESIS
using Noesis;
using NoesisApp;
#else
using Microsoft.Xaml.Behaviors;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows;
#endif
using NoesisGUIExtensions;
using System;

namespace Hdc.ObjectSystem.UserInterface.Helpers
{
    public class ChangeSpaceKeyToEnterBehavior : Behavior<ButtonBase>
    {
        public new ChangeSpaceKeyToEnterBehavior Clone()
        {
            return (ChangeSpaceKeyToEnterBehavior)base.Clone();
        }

        public new ChangeSpaceKeyToEnterBehavior CloneCurrentValue()
        {
            return (ChangeSpaceKeyToEnterBehavior)base.CloneCurrentValue();
        }

        protected override void OnAttached()
        {
            ButtonBase button = AssociatedObject;
            if (button != null)
            {
                button.PreviewKeyDown += OnPreviewKeyDown;
                button.PreviewKeyUp += OnPreviewKeyUp;
            }
        }

        protected override void OnDetaching()
        {
            ButtonBase button = AssociatedObject;
            if (button != null)
            {
                button.PreviewKeyDown -= OnPreviewKeyDown;
                button.PreviewKeyUp -= OnPreviewKeyUp;
            }
        }

        private void OnPreviewKeyDown(object sender, KeyEventArgs e)
        {
            ButtonBase button = AssociatedObject;
            if (button != null)
            {
                if (e.Key == Key.Space)
                {
                    e.Handled = true;
                    #if NOESIS
                    var args = new KeyEventArgs(button, ButtonBase.KeyDownEvent, Key.Enter, KeyStates.Toggled);
                    #else
                    var args = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Enter);
                    #endif
                    button.RaiseEvent(args);
                }
            }
        }

        private void OnPreviewKeyUp(object sender, KeyEventArgs e)
        {
            ButtonBase button = AssociatedObject;
            if (button != null)
            {
                if (e.Key == Key.Space)
                {
                    e.Handled = true;
#if NOESIS
                    var args = new KeyEventArgs(button, ButtonBase.KeyUpEvent, Key.Enter, KeyStates.Down);
#else
                    var args = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Enter);
#endif
                    button.RaiseEvent(args);
                }

            }
        }
    }
}

 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Changing GamepadAccept to work as Key_Enter instead of Key_Space

19 May 2023, 14:44

Is there some internal difference in Noesis when we pass GamepadAccept as opposed to keyboard space key?
Yes, we have some code to handle complex situations mixing keyboard key presses and gamepad button presses.
But I think we have something wrong in relation to the code handling the Enter key, because it should behave the same as with the Space key. Could you please report it in our bugtracker?

Anyway, I want to remark that using the Enter key to click the buttons has other implications. It means that the Button won't show the Pressed state or have the IsPressed property set to true. So you are probably missing some visual states in that case.
 
Sumel007
Topic Author
Posts: 30
Joined: 19 Mar 2020, 10:50

Re: Changing GamepadAccept to work as Key_Enter instead of Key_Space

21 May 2023, 19:40

Missing of pressed state is alright with us, but I'll keep it in mind in case we run into some strange issues with visual states in the future.

I've opened a ticket here https://www.noesisengine.com/bugs/view.php?id=2605. I'm not sure I understand it correctly, since you're saying that Enter key should behave the same as with Space key. Is it a different issue than the one I'm having (where the Behavior from my previous post translating Space key to Enter doesn't work when the Space keydown event is from Gamepad_Accept, but works when it's from keyboard's space key)? Or are these issues related and a fix to the code handling Enter keydown should make my Behavior work correctly with Gamepad_Accept?
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Changing GamepadAccept to work as Key_Enter instead of Key_Space

22 May 2023, 12:33

I meant that having the GamepadAccept pressed while a new Enter key press occurs (what you are trying to simulate) should behave the same as if the Space bar key was kept pressed. Our code is not correct in that situation, and fixing it will allow you to convert Space/GamepadAccept to Enter key down.

Thanks for the report!

Who is online

Users browsing this forum: Bing [Bot] and 12 guests