Is it possible, to capture (somewhere in app.xaml.cs i guess) any key and if it pressed open window?
Thanks for help!
There is a better way. Found this on a MS forum. Works like a charm.
Put this code in Application startup:
EventManager.RegisterClassHandler(typeof(Window),
Keyboard.KeyUpEvent,new KeyEventHandler(keyUp), true);
private void keyUp(object sender, KeyEventArgs e)
{
//Your code...
}
You could use something like this gist to register a global hook. It will fire whenever the given keys are pressed while your application is running. You can use it in your App class like this:
public partial class App
{
private HotKey _hotKey;
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
RegisterHotKeys();
}
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
UnregisterHotKeys();
}
private void RegisterHotKeys()
{
if (_hotKey != null) return;
_hotKey = new HotKey(ModifierKeys.Control | ModifierKeys.Shift, Key.V, Current.MainWindow);
_hotKey.HotKeyPressed += OnHotKeyPressed;
}
private void UnregisterHotKeys()
{
if (_hotKey == null) return;
_hotKey.HotKeyPressed -= OnHotKeyPressed;
_hotKey.Dispose();
}
private void OnHotKeyPressed(HotKey hotKey)
{
// Do whatever you want to do here
}
}
Yes and no.
Focus plays a role in the order for which a given key is handled. The control which captures the initial key press can opt to not pass the key along, which would prohibit you from capturing it at the top most level. In addition there are controls within the .NET framework that swallow certain keys under certain scenarios, however I am unable to recall a specific instance.
If your application is small and the depth is nothing more than a Window with buttons, this is certainly attainable and would follow the standard approach to capturing key strokes within a WPF application.
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl)
myVariable = true;
if (ctrl && e.Key == Key.S)
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl)
myVariable = false;
base.OnKeyUp(e);
}
If your application is large you can attempt a global hook as detailed here but understand that the aforementioned caveats can still exist.
Related
I am making a game where I need a constant keyboard listener (to navigate through the game). I tried getting the keyboard focus to one place and let it stay there using a seperate thread in a while true loop. This seems to crash my program.
Question:
Is there a method to get my keyboard focused on one element so I can grab my key input from there?
What can I use?:
something that works without throwing exceptions
something I can use in combination with other text input
something that doesn't take hours to compile
something that is easy to build another program (im not super good at c#)
What have I tried?
public MainWindow()
{
InitializeComponent();
Thread keyboardfocus = new Thread(GetFocus);
keyboardfocus.Start();
}
private void GetFocus()
{
while (true)
{
Keyboard.Focus(KeyboardButton);
}
}
private void KeyboardButton_OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Z)
{
map.PosUp -= 1;
MainCanvas.Background = Brushes.Aqua;
}
else if (e.Key == Key.S)
{
map.PosUp += 1;
MainCanvas.Background = Brushes.Black;
}
}
Thanks
Add event handler for Window.Loaded and set there a focus to the desired control:
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Keyboard.Focus(KeyboardButton);
}
Add event handler for the UIElement.LostKeyboardFocus in your case KeyboardButton and just set the keybord focus again to the KeyboardButton:
private void KeyboardButton_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
Keyboard.Focus(KeyboardButton);
}
I'm writing a simple wpf c# application for handling data in a database. A function that dynamically generates a ComboBox and a Textbox is executed from the Main TextBox when the tab-key is pressed down. Theoretically, it is supposed to switch focus to the next control, i.e. the newly generated ComboBox. Instead, when executed it moves to the latter generated TextBox. below is the code I have implemented.
Code Used:
private void Add_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
// insert generation code here
}
The above function is called when tab is pressed through this:
private void MainTextbox_KeyDown(object sender, KeyEventArgs e)
{
if(e.Key == Key.Tab)
{
Add_PreviewMouseDown(null, null);
}
}
Possible Reasons:
I think the issue might be with the time delay between the tab-key down and the process of creating the controls. Any thoughts?
Instead of writing your own key-handler, try overriding the existing one:
using System.Windows.Input;
//Later on:
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Key == System.Windows.Input.Key.Tab)
{
//Handle the tab key
}
}
You may, or may not need the base.OnKeyDown(e); cause that is probably what causes the default behavior of tab: Namely to shift focus to the next UI element in you application eg. the next textbox.
You could therefore try something like:
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key != System.Windows.Input.Key.Tab)
{
base.OnKeyDown(e); //Default behavior for all other keys
}else{
//Custom behavior for the tab key
}
}
I hope this helps :-)
Is there a possibility to handle WinKey+ArrowKey key combination before Windows handle it for WPFWindow? With OnPreviewKeyDown(KeyEventArgs e) I can catch when WinKey and ArrowKey are pressed separately, but not WinKey+ArrowKey combination. Seems that it is handled by system and window only get resizing command. Is there any way to handle this combination before system?
To do this, you will need to use a Global Keyboard Hook. There is a good project that would get you started in the right direction here: https://www.codeproject.com/Articles/19004/A-Simple-C-Global-Low-Level-Keyboard-Hook
To reiterate Hans Passant's warning, this will catch the key combination even if your program is running in the background. If this is not what you want, then you will need to subscribe and unsubscribe to the events when your program is focused/unfocused or put additional logic in there to detect whether your program is the focused program before taking any action.
If you import the classes from the link, then you can implement them in your code like this (EDIT: this seems to work with KeyValue, but not with KeyCode):
GlobalKeyboardHook gkh = new GlobalKeyboardHook();
private bool _winKeyPressed;
public MyConstructor()
{
gkh.HookedKeys.Add(Keys.Left); //37
gkh.HookedKeys.Add(Keys.Up); //38
gkh.HookedKeys.Add(Keys.Right); //39
gkh.HookedKeys.Add(Keys.Down); //40
gkh.HookedKeys.Add(Keys.LWin); //91
gkh.HookedKeys.Add(Keys.RWin); //92
gkh.KeyDown += gkh_KeyDown;
gkh.KeyUp += gkh_KeyUp;
}
private void gkh_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == 91 || e.KeyValue == 92)
{
// left or right windows key was released
_winKeyPressed = false;
}
}
void gkh_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyValue == 91 || e.KeyValue == 92)
{
// left or right windows key was pressed
_winKeyPressed = true;
}
if (e.KeyValue == 39 && _winKeyPressed == true)
{
// right key
MessageBox.Show("This works.");
}
}
I need to be able to detect if an "undo" has been triggered, and whether or not it has had an effect on the contents of my RichTextBox.
Of I type content into the RichTextBox at the minute, and press Ctrl+Z, windows seems to handle the undo for me. I want to be able to write code that will get triggered straight after that. I have been looking around and can't find anything.
Thanks in advance.
Starting from .Net 3.0, there is a simple built-in way to get notified when an undo command (among others) is executed:
CommandManager.RegisterClassCommandBinding(typeof(MyClass),
new CommandBinding(ApplicationCommands.Undo, OnUndo));
Just call this line of code in the static constructor (or somewhere else) and add a static method:
private static void OnUndo(object sender, ExecutedRoutedEventArgs e)
{
//your code
}
WINFORM:
You could exploit the KeyDown event and detect if Ctrl+Z is pressed:
richTextBox.KeyDown += new KeyEventHandler(richTextBox_KeyDown);
private void richTextBox_KeyDown(object sender, KeyEventArgs e){
if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Z){
//undo detected, do something
}
}
WPF :
richTextBox.KeyUp += new KeyEventHandler(richTextBox_KeyUp);
void richTextBox_KeyUp(object sender, KeyEventArgs e) {
if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.Z) {
//undo detected, do something
}
}
I think you're going to have to implement that yourself. I'm not aware of an event out of the box that will suit your needs.
You might also want to have a look at Monitored Undo Framework.
And here for additional reading.
If I well understand you, you want to compare content before and after the Ctr+Z.
Then you should do :
In XAML File :
<RichTextBox PreviewKeyDown="RichTextBox_PreviewKeyDown" KeyUp="RichTextBox_KeyUp" />
In CS File :
private void RichTextBox_KeyUp(object sender, KeyEventArgs e)
{
if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.Z)
{
Console.WriteLine("After : " + new TextRange(((RichTextBox)sender).Document.ContentStart, ((RichTextBox)sender).Document.ContentEnd).Text);
}
}
private void RichTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.Z)
{
Console.WriteLine("Before : " + new TextRange(((RichTextBox)sender).Document.ContentStart, ((RichTextBox)sender).Document.ContentEnd).Text);
}
}
Then, you will see in the output of your application the content of your RichTextBox before the Ctrl+Z and the content after.
I've try it and it works fine !
As already described, CommandBindings can be used. I prefer binding to each control instead of binding to all controls of a specific class. This can be done in the following way:
this.richTextBox.CommandBindings.Add(
new CommandBinding(ApplicationCommands.Undo, this.RichTextBoxUndoEvent));
private void RichTextBoxUndoEvent(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
this.richTextBox.Undo();
}
In my application I have:
private bool _clear = true;
This boolean is used to see if a textbox should be cleared or not when user enters a new text into it (by pressing on a TreeNode in a TreeView).
Then I have these two events for my form:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Modifiers == Keys.Control)
{
_clear = false;
}
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.Modifiers == Keys.Control)
{
_clear = true;
}
}
I want it somehow when user is holding the CTRL key, clear be FALSE and when CTRL is released, clear goes back to TRUE.
Obviously the code I wrote here, does not work! what can be wrong and/or is there a better way?
It's a simple fix, as when you release the key, the KeyUp event does not receive any info of the key released itself, so just set the property to true:
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
_clear = true;
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Modifiers == Keys.Control)
{
_clear = false;
}
}
If you want to see it work in real time, add a label to your form and add this under each setting of the '_clear' variable:
label1.Text = _clear.ToString();
Per your comment, change the second code block to:
if (e.KeyData.ToString() == "ControlKey, Control")
{
_clear = false;
}
else if(other shortcut conditionals go here or on other else if's)
{
_clear = true;
}
The only time this conditional will hold true is when control is held by itself. The else case is there for the purpose of setting _clear to true when you press ctrl followed by another key, due to the fact that as soon as you press control, it will fire the KeyDown event.
Based on this change, as long as you take care of the key presses following that if statement, (such as else if()'s), you will not need to set anything in the KeyUp event.
See my answer here to the intricacies of keys and their properties if you want some more in-depth info.
Edit #3 :
As long as you set the _clear to true on the first line in each conditional, you should be able to avoid the problem you are facing in your comment:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData.ToString() == "ControlKey, Control")
{
_clear = false;
}
else if(e.KeyData.ToString() == "O, Control")
{
_clear = true;
//Do other stuff here, such as opening a file dialog
}
}
It is much easier if you do this the other way around. Check if the CTRL key is down in the treeview's event. Something like this:
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) {
if ((Control.ModifierKeys & Keys.Control) == Keys.Control) {
// Control key is down, do something...
}
}
You need to change the KeyPreview property of your form to True.