Canceling the SpaceBar Click/Tap on uwp controls throughout the app - c#

When a UI element ( control ) is focused in a uwp app it can be triggered with Spacebar or the Enter keys, this is not limited to Desktop but also helps in Xbox so user can navigate through the controls and press on any focused control to active its Command.
Use case
But in My use case I want only Enter key to trigger that behaviour and Spacebar should not do anything at all no matter which control is pressed on the screen.
The reason to this requirement is that I am building a MediaPlayer application and no matter which control or button is focused within the app when I press Spacebar I want to simply link it to the Play/Pause Behaviour of my media element.
Not a Duplicate
This question is not a duplicate of : UWP - Don't fire Click event when pressing space (like in Movies & TV app)
Because in the question linked above, the answer was only relevant if any of the AppBarButtons were focused so they will not do anything on pressing Space but only will be invoked with Enter. But in my use case I want to apply the same behavior even outside the MediaPlayerElement control. I have a NavigationView and MediaPlayerElement resides in one of the pages, so I want this behavior to work even when a NavigationViewItem is focused or any other control which can be focused and invoked should only be invoked with Enter and not Space.
Is there a app level solution where I can apply this behaviour at the very root control and it descends to all of its children i.e : whole app?
What I have tried
I have tried with the already answered question (linked above) and that works fine for its limited scenario. And I have also tried setting AllowFocusOnInteraction=false to every app bar button and also other extra controls I have in the style of my CustomMediaTransportControls. But this is also limited to MediaPlayerElement only and also it prevents tab navigation which is not good for accessibility.

You can do this by handling the PreviewKeyDown event higher in the visual tree hierarchy, for example in the Page.
Subscribe to the event in the Page constructor:
public MainPage()
{
this.InitializeComponent();
this.PreviewKeyDown += MainPage_PreviewKeyDown;
}
Or in XAML:
<Page ... PreviewKeyDown="MainPage_PreviewKeyDown">
And in the event handler set the KeyRoutedEventArgs to handled when the Space key was pressed:
private void MainPage_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == VirtualKey.Space)
{
e.Handled = true;
}
}
This way the key down event will never reach any control below in the hierarchy because the PreviewKeyDown event propagates the tree before the event takes place.

There are many ways could approach, You could listen the current Content PreviewKeyDown event to detect Space press.
public Scenario1()
{
this.InitializeComponent();
Window.Current.Content.PreviewKeyDown += Content_PreviewKeyDown;
}
private void Content_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
{
e.Handled = e.Key == VirtualKey.Space ? true : false;
}
You could also GLOBAL HOTKEY for your uwp app that could be used when your app's window not in foreground. For more derail you could check this blog .

Related

Making sure that a C# form has focus when it should

I am a fairly new to Visual C# but have coded in Delphi for a long time. I have created a form that has a simple panel that is hidden unless you type in a particular key on the keyboard (I do have "KeyPreview" set for true for the form and I am using the KeyDown event to handle determining if the correct key was pressed and to make the panel visible/invisible). Just beneath the panel is a webBrowser component.
What is happening is as follows:
When my form initially starts, I have code for the "Shown" event that makes sure the form has focus initially:
private void Form1_Shown(object sender, EventArgs e)
{
if (!Focused)
{
Focus();
}
}
When the form is focused at this point, my code for detecting the proper keystroke to get the panel to appear or disappear works fine.
Here is where things get strange and I'm not sure of what to do. There are two parts I am dealing with for what is wrong:
If I click on another form and then on the caption bar of my form again to get focus on my form and try a keystroke, the keystroke detection does not work. However, if I click on another form and then back on my form one more time, the keystroke detection for the form does work. What can I do to make sure that this works each time my from has focus again?
If I click on the web browser component within my own form, the KeyDown code for the form no longer gets enacted. Even if I click on the caption bar for the form, the KeyDown event does not work. What do I need to do to assure that, if a component within my form is clicked, my form will still respond for the KeyDown event?
Thanks in advance for any advice.
I can't say why your caption bar seems to be intercepting key events. It may be that various components on the form can have focus and thus capture keyboard events. I know the web browser control works this way. You may consider capturing keyboard events globally.
I saw something on Codeproject that shows how to do this. I hope this helps.
They use UserActivityHooks.
UserActivityHook actHook;
void MainFormLoad(object sender, System.EventArgs e)
{
actHook= new UserActivityHook(); // crate an instance
// hang on events
actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved);
actHook.KeyDown+=new KeyEventHandler(MyKeyDown);
actHook.KeyPress+=new KeyPressEventHandler(MyKeyPress);
actHook.KeyUp+=new KeyEventHandler(MyKeyUp);
}
As for the webbrowser control, of course it is going to interecept keyboard events. Users often have to enter text in forms and developers often code javascript on webpages to specifically hook into keyboard events. So the webbrowser control must be able to capture those.

C#: KeyDown Event does not work in controls

I am trying to finish my final school project. I am creating a c# winform game to be specific. We can not use anything else.
I will not be posting here code because I got it pretty messed up and I guess u can answer me just with this info.
Setup:
I got my program set up like this. The is main form and two user controls. I switch those controls within the main form during the game. The first one is MENU and the second one is GUI with picturebox acting as a gamescene.
Problem:
Setup quite not important I guess. But what I need to do is to do some action when I press key Down on the first Control (while it is active in the form). Sounds easy I thought at first but the onKeyDown event in the menu.cs(1st usercontrol) is doing nothing when i press the key(The event method is not blank). I tried this.previewKey = true; in the menu load method but it did not even recognize it.
So my question is: Is there any way to use onKeyDown in usercontrols code?
I did it this way becouse I use the same keys in the second controls and i didnt want it to get messy (which obviously did the oposite huh)
TLDR: Need to use onKeyDown event in userControls (keyPreview might be the key)
BONUS
I also need to somehow link variables from Controls 1 to Form and Controls 2.
I looked it up and found out it would be easy in situacion like "Form to Form" but since it is userControls I cant figure it out and I feel like I am just a tiny bit from finishing it.(feels terrible sitting here 9 hours xD please help)
On the keypress event make sure it is for the selected control an not the main form. If you are capturing for the form to determine which key was pressed then use the keypress event for that. You can use a messagebox to verify that you have the right control. Every key has an integer value and you can access and use those by using the properties of e.
Bonus. Depending on how you implemented your code you will have to use either global varibles to pass the data across the forms or use delegates to actively access and set controls on another form
You have to register the event in the Form.Designer.cs :
private void InitializeComponent()
{
// Your form properties here
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
}
You're KeyDown event can be used like this in the Form.cs code :
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
// To know if your event is working and the value of the key who's pressed
MessageBox.Show("Key Pressed = "
+ e.KeyCode.ToString()
+ ", Value = "
+ e.KeyValue.ToString());
// Example - add some actions bellow
if (e.KeyValue == 13)
MessageBox.Show("Return Key Pressed");
}

Key Event doesn't actives by arrow keys

first of I'm working with WPF and i'm new to it.
I added a KeyDownEvent to a content control in xaml:
<ContentControl Grid.Row="1" Name="dockingContentControl" KeyDown="dockingContentControl_KeyDown"/>
I know, probably there is a better way to add a KeyDown event.
(Would also help)
But the event is working. So I used a simple Console.WriteLine command like so:
private void dockingContentControl_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
Console.WriteLine(e.Key);
}
and it showed me the buttons I pressed.
But somehow it did not trigger with the Arrowkeys.
I don't know why all other (I think all, didn't test all) buttons are working, but the Arrowkeys not.
Did I miss something or did I have to add some kind of extra code.
Commend: All other buttons are recognized, with the exception of the fn-button.
The background chart is moving, could it be that the chart has the focus and doesn't "forward" the input?
It depends what Controls you have placed inside your ContentControl and what control has the focus. Some keys like TAB, RETURN, ESC, and arrow keys, are typically ignored by some controls because they are not considered input key presses. The arrow keys are considered navigation keys and pressing these keys typically do not raise the KeyDown (for a Button as an example)
You can try to use the PreviewKeyDown-Event for this case.
If I use your provided code in a minimal solution I receive the KeyDown-Events for all keys, but it is required that the ContentControl has the focus.
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
dockingContentControl.Focus();
}
private void dockingContentControl_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
Console.WriteLine(e.Key);
}
}

Equivalent of 'KeyPreview' property in WinRT Metro

I am writing a metro app where it makes sense for focus to jump to a single text box anytime the user starts typing. But I can't figure out how to implement this functionality locally, without modifying other user controls to detect keydown and forward focus to the text box.
In WinForms I would have used the form's "KeyPreview" property, which caused any key presses within the form's controls to fire form KeyDown/KeyPress/KeyUp events. I can't find any equivalent in metro.
I tried the naive solution of just forcing focus to the text box anytime it left, but that has obvious problems (e.g. buttons flicker instead of staying highlighted when you click and hold on them).
How can I ensure any keyboard typing goes to a specific text box?
The event needs to be placed on the current core window, which is the root element all controls are nested on.
Windows.UI.Xaml.Window.Current.CoreWindow.KeyDown += (sender, arg) => {
// invoked anytime a key is pressed down, independent of focus
}
Here you go ...
Responding to keyboard input (Metro style apps using C#/VB/C++ and XAML)
&&
Implementing keyboard accessibility (Metro style apps using C#/VB/C++ and XAML)
Pay special attention to routed events. There are examples there too.
Hope this helps.
In your xaml code u bind these to events to page::
Loaded="pageRoot_Loaded_1"
Unloaded="pageRoot_Unloaded_1"
and inside these methods u have to bind and unbind ur events for keydown or keypress
private void pageRoot_Loaded_1(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
}
private void pageRoot_Unloaded_1(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.KeyDown -= CoreWindow_KeyDown;
}

UserControl Keyboard Focus

I got a form with a number of buttons on it (assume 20). In the middle, I got a User Control which is completely empty. The question is: how can I make it so that when the User Control is clicked, it will get keyboard focus?
Reason: I paint shapes in that User Control, with my mouse. The shapes are actually other User Controls. What I want to do is be able to use the keyboard to move those shapes. But I cannot seem to correctly be able to grab the Keyboard focus. The Key_Down events just don't reach my main (drawing into) User Control.
So, in other words, how can we have keyboard focus in a control has no focusable items on it? How can one make an keyboard-unfocusable control, catch those events? Any way of grabbing these events window-wide, other than going raw-WIN32 API hardcore?
A UserControl was very much designed to be a container control for other controls. It abhors getting the focus and tries to pass it off first chance it gets. You should not be using a UserControl here, given that you don't put any controls inside of it. A Panel control will suffice. Which has the exact same problem, it doesn't want to get focus either.
Surgery is required to override its behavior. Everything you need is in this answer.
Add this to your user control code to capture keyboard input:
/// <summary>Keys which can generate OnKeyDown event.</summary>
private static readonly Keys[] InputKeys = new []
{ Keys.Left, Keys.Up, Keys.Right, Keys.Down, };
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
if(Array.IndexOf<Keys>(InputKeys, e.KeyCode) != -1)
{
e.IsInputKey = true;
}
base.OnPreviewKeyDown(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
// just to illustrate this works
MessageBox.Show("KeyDown: " + e.KeyCode);
}
See http://msdn.microsoft.com/en-us/library/aa969768.aspx. You can assign keyboard focus by
1. Set the usercontrol.Focusable=true;
2. Use Keyboard.Focus(usercontrol).
You need to set the CommandRouting flag on your control to true.
The command routing dependency property is defined in a public API (MS.VS.Editor.dll) and your adornment will want to use that API to indicate that it is handling its commands instead of allowing the containing text view handle them. You can do this with from your control’s initialization.
Microsoft.VisualStudio.Editor.CommandRouting.SetInterceptsCommandRouting(this, true);

Categories

Resources