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);
}
Related
I am working on a Xamarin project and I need to be able to tell if the changes that occur to the text in an Entry view are from the code or from the UI, is this possible in Xamarin? or is there a known work around to do this.
I know about the OnTextChanged event but this only tells you that the Text property has changed, and gives you access to the old and new value of the Text property. It does not differentiate between different causes of text change.
You can get some idea from this thread, check if the entry is focused to differentiate between different causes of text change:
public MainPage()
{
InitializeComponent();
myEntry.TextChanged += MyEntry_TextChanged;
}
private void MyEntry_TextChanged(object sender, TextChangedEventArgs e)
{
var entry = sender as Entry;
if (entry.IsFocused)
{
//change from UI
Console.WriteLine("change from UI");
}
else{
//change from code
Console.WriteLine("change from code");
}
}
Update: The better way to solve op's problem:
You can set a flag yourself that tells your code to ignore the event. For example:
private bool ignoreTextChanged;
private void textNazwa_TextCanged(object sender, EventArgs e)
{
if (ignoreTextChanged) return;
}
Create a method and use this to set the text instead of just calling Text = "...";::
private void SetTextBoxText(TextBox box, string text)
{
ignoreTextChanged = true;
box.Text = text;
ignoreTextChanged = false;
}
Refer: ignoreTextChanged
you can use EntryRenderer to detect keypress event and use that flag to detect the change by code or by UI.
Here are the step:
- Exetend your entry control with new event OnTextChangeByUI
- Write custom render for both platform
e.g for android it will be something like this
public class ExtendedEntryRender : EntryRenderer
{
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Control != null)
{
Control.KeyPress += ((Entry)Element).OnTextChangeByUI;
}
}
}
When I press enter, which enables the buttonEditClient_PressEnter function,
the buttonEditClient_ButtonClick function should be called.
private void buttonEditClient_PressEnter(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
//fire buttonEditClient_ButtonClick function
}
}
private async void buttonEditClient_ButtonClick(object sender, ButtonPressedEventArgs e)
{
//buttonEditClient_ButtonClick activated
}
In the Designer:
this.buttonEditClient.ButtonClick += new DevExpress.XtraEditors.Controls.ButtonPressedEventHandler(this.buttonEditClient_ButtonClick);
this.buttonEditClient.KeyDown += new System.Windows.Forms.KeyEventHandler(this.buttonEditClient_PressEnter);
If I try this:
private void buttonEditClient_PressEnter(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
buttonEditClient_ButtonClick(sender, e)
}
}
I get this error:
cannot convert from 'System.Windows.Forms.KeyEventArgs' to 'DevExpress.XtraEditors.Controls.ButtonPressedEventArgs'
How can I activate the buttonEditClient_ButtonClick function?
A click event is inherently different from a keyboard event (e.g., one includes information about the pressed mouse button and cursor position, the other about the pressed key), so you can't pass your KeyEventArgs to the click handler, which expects a ButtonPressedEventArgs.
You have a few simple options here:
Move your code from the button click handler to an extra function, and call that from both your handlers.
Find a way to create a new ButtonPressedEventArgs instance inside the key handler, and then pass that instead of the KeyEventArgs. This would be a very slipshod solution, as you're literally making stuff up (what cursor position are you going to give it?).
The first solution could look something like this:
private void buttonEditClient_PressEnter(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
buttonEditClientSubmit();
}
}
private async void buttonEditClient_ButtonClick(object sender, ButtonPressedEventArgs e)
{
buttonEditClientSubmit();
}
private void buttonEditClientSubmit()
{
// your code...
}
It depends on if you actually need anything from the ButtonPressedEventArgs. If you don't need anything from ButtonPressedEventArgs, you could just have both events call one function.
private void Handle_buttonEditClient()
{
// Do what you want to do when the button is pressed or has the "Enter"
// key pressed on it.
}
private void buttonEditClient_PressEnter(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
Handle_buttonEditClient();
}
}
private void buttonEditClient_ButtonClick(object sender, ButtonPressedEventArgs e)
{
Handle_buttonEditClient();
}
Note
I made buttonEditClick_ButtonClick synchronous, but if you leave it async the same thing applies. Just have both events call the same function.
If you need the ButtonPressedEventArgs, then it's like Anas Alweish says. You'll have to create an instance of ButtonPressedEventArgs. I'm not familiar with DevExpress, so I don't know how you'd do that. Maybe something like new ButtonPressedEventArgs(buttonEditClient)?;
DevExpress Docs on ButtonPressedEventArgs
I have a program containing multiple C# Forms TextBoxes. I've set up Hotkeys for the entire form activating certain functions. My problem is that my Hotkeys have been set onto the Form KeyDown event and they activate if I write something on a TextBox.
Example: One Hotkey might be I. Everytime I write the letter onto a textbox the Hotkey activates.
Alterior solutions and problems: I've thought about putting a Key in front of the Hotkey like CTRL+Hotkey, but these also present problems as CTRL+C is Windows Copy command etc. SHIFT is an UpperKey button.
Question: Can I prevent Hotkeys from activating when I am writing onto a TextBox without having to go through all of them in the form?
EDIT: Some code as requested. The button codes come from a stored XML file or the Hotkeys Form+Class (separate) where I've set up a window for them.
public Hotkeys hotkeysForm = new Hotkeys();
void Form1_KeyDown(object sender, KeyEventArgs e)
{
toggleInformation = hotkeysForm.toggleInformation;
if (e.Control && e.KeyCode == toggleInformation)
{
showInfo(true);
}
else if (e.KeyCode == toggleInformation)
{
if (!isInfoActive)
showInfo();
else
hideInfo();
}
}
You can disable hotkeys while texbox is an active control. Add the Enter and Leave events for all textboxes:
private void textBox_Enter(object sender, EventArgs e)
{
KeyPreview = false;
}
private void textBox_Leave(object sender, EventArgs e)
{
KeyPreview = true;
}
You should try this hack, if it could solve your problem,
Create a Extented TextBox and use it in your code. you can handle whether to write the pressed key in textbox or not in hotkeyPressed check.
public class ETextBox : System.Windows.Forms.TextBox
{
protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
{
if (hotKeyPressed) // this is the condition when you don't want to write in text.
{
//Do whatever you want to do in this case.
}
else
{
base.OnKeyDown(e);
}
}
}
I want to activate a textbox when users starts typing in my Windows 8.1 Store app.
I tried handling KeyDown event of Page, something like this code:
private void pageRoot_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (SearchBox.FocusState == Windows.UI.Xaml.FocusState.Unfocused)
{
string pressedKey = e.Key.ToString();
SearchBox.Text = pressedKey;
SearchBox.Focus(Windows.UI.Xaml.FocusState.Keyboard);
}
}
But the problem is e.Key.ToString() always returns capital english character of the pressed key, while user might be typing in another language. For example, the Key D types ی in Persian keyboard, and user might want to type in Persian, but e.Key.ToString() will still return D instead of ی.
Also I tried making that textbox always focused (my page contains some gridviews and so on, and a textbox) and while this solution works on PCs, it makes the on-screen keyboard to always appear on tablets.
So, what should I do? Is there any way to get the exact typed character in KeyDown event?
As Mark Hall suggested, It seemed that CoreWindow.CharacterReceived event can help solving this issue.
So, I found the final answer here.
This is the code from that link:
public Foo()
{
this.InitializeComponent();
Window.Current.CoreWindow.CharacterReceived += KeyPress;
}
void KeyPress(CoreWindow sender, CharacterReceivedEventArgs args)
{
args.Handled = true;
Debug.WriteLine("KeyPress " + Convert.ToChar(args.KeyCode));
return;
}
But this event will fire anywhere independent of current active page. So I must remove that event when user navigates to another page, and add it again when user comes back.
Update: I also had to move the cursor of the textbox to the end of the text, so user can write naturally. Here's my final code:
private void KeyPress(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.CharacterReceivedEventArgs args)
{
if (SearchBox.FocusState == Windows.UI.Xaml.FocusState.Unfocused)
{
SearchBox.Text = Convert.ToChar(args.KeyCode).ToString();
SearchBox.SelectionStart = SearchBox.Text.Length;
SearchBox.SelectionLength = 0;
SearchBox.Focus(FocusState.Programmatic);
}
}
private void pageRoot_GotFocus(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.CharacterReceived += KeyPress;
}
private void pageRoot_LostFocus(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.CharacterReceived -= KeyPress;
}
I WPF I need to set a boolean variable (and additionally perform some other actions) while a key is pressed. I.e. to set on the key is pressed, and to reset on the key is released. Something that I can do by just event handlers:
this.KeyDown += new KeyEventHandler(MyModuleView_KeyDown);
this.KeyUp += new KeyEventHandler(MyModuleView_KeyUp);
bool MyFlag = false;
void MyModuleView_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Space)
{
MyFlag = false;
...
}
}
void MyModuleView_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Space)
{
MyFlag = true;
...
}
}
But I suspect in WPF it can be done in a more correct way.
I'm trying to use a command approach, but in the way I do it I can only set a variable on the fact of pressing a key but not while a key is pressed.:
private static RoutedUICommand mymode;
InputGestureCollection inputs = new InputGestureCollection();
inputs.Add(new KeyGesture(Key.Space, "Space"));
mymode = new RoutedUICommand("MyMode", "MyMode", typeof(InterfaceCommands), inputs);
public static RoutedUICommand MyMode
{
get { return mymode; }
}
...
private void MyModeCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
MyFlag = true;
...
}
How to correctly track the state of a key in WPF for turning on something (for example selection mode of a cursor) while the key is pressed?
Commands will not help you here, your approach with events is a right way to go. If you don't like to have a code-behind - you can create a custom attached property, which would be responsible for events wiring.
Have a look at AttachedCommandBehavior library and examples provided