I have a problem that I'm struggling with..
I want to move an image using my keyboard to the left, right, up or down and in a diagonal way.
I searched the web and found, that to use 2 diffrent keys I need to remember the previous key, so for that I'm using a bool dictionary.
in my main Form class this is how the KeyDown event looks like:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
baseCar.carAccelerate(e.KeyCode.ToString().ToLower());
carBox.Refresh(); //carbox is a picturebox in my form that store the image I want to move.
}
My KeyUp event:
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
baseCar.carBreak(e.KeyCode.ToString().ToLower());
}
My Paint event:
private void carBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(Car, baseCar.CharPosX, baseCar.CharPosY); // Car is just an image
}
And my baseCar class:
private Dictionary KeysD = new Dictionary();
// there is a method to set the W|A|S|D Keys, like: KeysD.Add("w",false)
public void carAccelerate(string moveDir)
{
KeysD[moveDir] = true;
moveBeta();
}
public void moveBeta()
{
if (KeysD["w"])
{
this.CharPosY -= this.carMoveYSpeed;
}
if (KeysD["s"])
{
CharPosY += carMoveYSpeed;
}
if (KeysD["a"])
{
CharPosX -= carMoveXSpeed;
}
if (KeysD["d"])
{
CharPosX += carMoveXSpeed;
}
}
public void carBreak(string str)
{
KeysD[str] = false;
}
Anyway it works, but my problem is that I can't get back to the first pressed key for example:
I pressed W to move up and then the D key to go diagonal, how ever when I release the D key it wont go Up again because the KeyDown event is "dead" and wont call the carAccelerate() method again..
and I can't figure out how to fix it..
Can any one help me please?
Maybe there is a better way to handle the keys? im open to any ideas!
And I hope you can understand it, my english isnt the best :S
Store all keystates and don't animate on keypress, but for example using a timer.
Then:
KeyDown(key)
{
KeyState[key] = true;
}
KeyUp(key)
{
KeyState[key] = false;
}
Timer_Tick()
{
Animate();
}
Animate()
{
if (KeyState["W"])
{
// Accelerate
}
if (KeyState["S"])
{
// Decelerate
}
}
Then in the KeyDown method you can check for conflicting keys (what if accelerate + decelerate are pressed at the same time, and so on).
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);
}
Ok, so in my program I tried making buttons and assigning different methods for each button pressed. But I came into a problem where I also want the user to use his keyboard and assign buttons pressed on keyboard into same buttons on screen. Yet firstly, I tried if button is pressed by mouse or keyboard yet the method doesn't allow KeyEvents in 'EventArgs' (which is fine by me), so I created different method and made a boolean variable so that if in that separate method the key is pressed, make that variable true and in that main method if that is true then perform the code, yet the program ignores that keyboard variable and I have no idea why.
Then I tried making a different class as I thought maybe that would help. Now I can call that class and method inside it but not pass a parameter as it says it's a method so it can't do anything else but only be called.
If you're curious, here's the code below...
___
// the button '1' variable
bool pressOne = false;
___
// method for if that button is pressed
private void AnyNumberClick(object sender, EventArgs e)
{
Button btnSender = (Button)sender;
if (btnSender == btn_Num1 || pressOne)
{
// if button is pressed by either, perform code
}
}
___
// method for detecting which key is pressed for certain bool variable into button's method
public void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.D1)
{
pressOne = true;
}
else
{
pressOne = false;
}
___
// Call another class inside 'From1_KeyDown' method
Class1 newclass = new Class1();
newclass.buttonused();
NumResult.Text = newclass.buttonused.num();
The one with class I don't know how to start it. I don't even know if new class will help me there or not. I did the research but didn't find the answer. I appreciate any help from this.
Try it this way. I've setup a Dictionary<Keys, Button> to represent the relationship between a Key and a Button. Then I've overridden ProcessCmdKey() to trap key presses. If the key pressed exists in our lookup, then we click it with .PerformClick():
public partial class Form1 : Form
{
private Dictionary<Keys, Button> btnLookups = new Dictionary<Keys, Button>();
public Form1()
{
InitializeComponent();
// make your key -> button assignments in here
btnLookups.Add(Keys.F1, button1);
btnLookups.Add(Keys.F2, button2);
btnLookups.Add(Keys.F3, button3);
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
Button btn;
if (btnLookups.TryGetValue(keyData, out btn))
{
btn.PerformClick();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("button1");
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("button2");
}
private void button3_Click(object sender, EventArgs e)
{
MessageBox.Show("button3");
}
}
You need an event handler to tie to your method "AnyNumberClick". This is done in the Designer.cs portion of your form. Create a character array char[] and create a function within a button pressed event method, and then compare the button pressed against the set of characters in your array.
private void txt_box_keypress(object sender, KeyPressEventArgs e)
{
char[] SomeArray = {'a','b','c', etc};
int LengthOfArray = SomeArray.Length;
for (int x = 0; x < LengthOfArray; x++)
{
if (txt_box.Text.Contains(SomeArray[x]))
{
'Your method event here'
}
}
}
I am trying to make a WinForm ListBox in which you can loop trough using the arrow keys. I also have two buttons on which you can click to go up and down the list. The buttons do produce the desired effect. The problem is that the ListBox's keyDown event is never triggered
public MainForm()
{
InitializeComponent();
if (this.clipboardHistoryList.Items.Count > 0)
this.clipboardHistoryList.SetSelected(0, true);
clipboardHistoryList.Select();
}
private void goUpButton_Click(object sender, EventArgs e)
{
goUpList();
}
private void goDownButton_Click(object sender, EventArgs e)
{
goDownList();
}
private void goDownList()
{
if (clipboardHistoryList.SelectedIndex == clipboardHistoryList.Items.Count - 1)
{
clipboardHistoryList.SetSelected(0, true);
}
else
{
clipboardHistoryList.SetSelected(clipboardHistoryList.SelectedIndex + 1, true);
}
}
private void goUpList()
{
if (clipboardHistoryList.SelectedIndex == 0)
{
clipboardHistoryList.SetSelected(clipboardHistoryList.Items.Count - 1, true);
}
else
{
int l_currentlySelected = clipboardHistoryList.SelectedIndex;
clipboardHistoryList.SetSelected(l_currentlySelected - 1, true);
}
}
private void clipboardHistoryList_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up) //Brekpoint is never reached
{
goUpList();
}
else if (e.KeyCode == Keys.Down)
{
goDownList();
}
}
I have put the MainForm's keypreview proprety to true.
The arrow keys do work by default on a listbox but they won't let you go from last to first element if you press the down arrow on the last element --hopes this makes sense.
EDIT
I have seen on Microsoft's documentation that I need to override the ProcessDialogKey method but I am not exactly sure of what I need to do.
Perform special input or navigation handling on a control. For example, you want the use of arrow keys in your list control to change the selected item. Override ProcessDialogKey
Is there already a built-in way to enable this behaviour?
What did I miss?
Thanks!
From looking at the code in your Designer.cs file, it doesn't look like you've actually got your clipboardHistoryList control wired into your clipboardHistoryList_KeyDown event handler. You can do that through the "Events" subtab of the Properties window in your visual studio form designer (look for the little lightning bolt icon) and wire up the event through the designer that way, or alternatively you can do it in code:
public MainForm()
{
InitializeComponent();
if (this.clipboardHistoryList.Items.Count > 0)
this.clipboardHistoryList.SetSelected(0, true);
clipboardHistoryList.Select();
clipboardHistoryList.KeyDown += clipboardHistoryList_KeyDown;
}
In my program I would need that an action is perfomed while a key is pressed. I have already searched but the solutions either were not for c#, neither for forms or I couldnt understand them.
Is there a proper and easy solution to this?
EDIT: I am using WinForms and I want that while the form is focussed and a key is pressed an action is repeatedly performed.
First off, you need to provide a bit more information and if possible some code you already tried. But nevertheless I'll try. The concept is relatively easy, you add a timer to your form, you add key_DOWN and key_UP events (not key pressed). You make a bool that resembles if key is currently pressed, you change its value to true on keydown and false on keyup. It will be true while you hold the key.
bool keyHold = false;
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (keyHold)
{
//Do stuff
}
}
private void Key_up(object sender, KeyEventArgs e)
{
Key key = (Key) sender;
if (key == Key.A) //Specify your key here !
{
keyHold = false;
}
}
private void Key_down(object sender, KeyEventArgs e)
{
Key key = (Key)sender;
if (key == Key.A) //Specify your key here !
{
keyHold = true;
}
}
**If you're trying to make a simple game on forms and you're struggling with the input delay windows has (press and hold a key, it will come up once, wait and then spam the key) This solution works for that (no pause after the initial press).
You can try this.
In the Key down event you set the bool 'buttonIsDown' to TRUE and start the method 'DoIt' in an Separate Thread.
The code in the While loop inside the 'DoIt' method runs as long the bool 'buttonIsDown' is true and the Form is on Focus.
It stops when the Key Up event is fired or the Form loose the focus.
There you can see the 'buttonIsDown' is set to false so that the While loop stops.
//Your Button Status
bool buttonIsDown = false;
//Set Button Status to down
private void button2_KeyDown(object sender, KeyEventArgs e)
{
Key key = sender as Key;
if (key == Key.A)
buttonIsDown = true;
//Starts your code in an Separate thread.
System.Threading.ThreadPool.QueueUserWorkItem(DoIt);
}
//Set Button Status to up
private void button2_KeyUp(object sender, KeyEventArgs e)
{
Key key = sender as Key;
if (key == Key.A)
buttonIsDown = false;
}
//Method who do your code until button is up
private void DoIt(object dummy)
{
While(buttonIsDown && this.Focused)
{
//Do your code
}
}
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