Detect whether CapsLock is on or off in Silverlight - c#

You may find if the CapsLock key has been pressed subscribing to the KeyDown/KeyUp event. And then toggle the state of the CapsLock based on that input. The problem with this approach is that you need the initial state of the CapsLock key to start toggling that.
One application of this could be giving the user a notification on a Login Page (this is what i need).
By the way i'm using Silverlight 5.
EDIT
The solution posted here says:
You can however find out if Capslock is on by making use of
KeyEventArgs.PlatformKeyCode that's actually send at onKeyDown.You can
look up the Virtual Key-code for capslock in here:
http://msdn.microsoft.com/en-us/library/ms927178.aspx
With this solution you can't determine the CapsLock state, because KeyEventArgs.PlatformKeyCode returns "an integer value that represents the key that is pressed or released (depending on which event is raised)". So if CapsLock is On and Key A is pressed then KeyEventArgs.PlatformKeyCode = 65, and on the other hand if CapsLock is off and Key A is pressed then KeyEventArgs.PlatformKeyCode = 65.
In other words you can't determine if the CapsLock is enabled or not based on the KeyEventArgs.PlatformKeyCode property.
The answer to this question also seems to have a solution, it checks two things:
the letter typed is Upper Case and Shift isn't pressed
the letter typed is Lower Case and Sift is pressed
Both of this cases implies that the CapsLock is On, but there is also a problem with this solution, given a KeyEventArgs you can know the pressed key in the keyboard but can't know the Char outputted by that key.

I'd suggest using a Behavior for this detection since you can hook into the PasswordChanged and KeyDown events to determine if the Caps Lock is on. Here is a quick behavior I wrote to detect if the Caps Lock is on. You can bind to the CapsLockOn behavior and use something like a data state behavior to hide/show your warning message.
public class DetectCapsLockBehavior : Behavior<PasswordBox>
{
private int _lastKey;
private ModifierKeys _modifiers;
[Category("Settings")]
public bool CapsLockOn
{
get { return (bool)GetValue(CapsLockOnProperty); }
set { SetValue(CapsLockOnProperty, value); }
}
public static readonly DependencyProperty CapsLockOnProperty = DependencyProperty.Register("CapsLockOn", typeof(bool), typeof(DetectCapsLockBehavior), new PropertyMetadata(null));
protected override void OnAttached()
{
AssociatedObject.PasswordChanged += new RoutedEventHandler(AssociatedObject_PasswordChanged);
AssociatedObject.KeyDown += new KeyEventHandler(AssociatedObject_KeyDown);
}
void AssociatedObject_KeyDown(object sender, KeyEventArgs e)
{
_lastKey = e.PlatformKeyCode;
_modifiers = Keyboard.Modifiers;
}
void AssociatedObject_PasswordChanged(object sender, RoutedEventArgs e)
{
if (_lastKey >= 0x41 && _lastKey <= 0x5a)
{
var lastChar = AssociatedObject.Password.Last();
if (_modifiers != ModifierKeys.Shift)
{
CapsLockOn = char.ToLower(lastChar) != lastChar;
}
else
{
CapsLockOn = char.ToUpper(lastChar) != lastChar;
}
}
}
}
NOTE: This is sample code, so there could be bugs. Just trying to demonstrate how it could be done.

region KeysDetection
bool bCaps = false;
bool bIns = false;
bool bNum = false;
public void FloatableWindow_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.CapsLock:
bCaps = !bCaps;
lbl_caps.Opacity = (bCaps) ? 1 : 0.5;
break;
case Key.Insert:
bIns = !bIns;
lbl_ins.Opacity = (bIns) ? 1 : 0.5;
break;
case Key.Unknown:
{
if (e.PlatformKeyCode == 144)
{
{
bNum = !bNum;
lbl_num.Opacity = (bNum) ? 1 : 0.5;
}
}
break;
}
}
}
#endregion

Related

C# moving object with keys doesnt work like i want [duplicate]

So in short i'm simply trying to move a rectangle around a Canvas object in a WPF application. What i have here is my KeyDown event function. The problem is, when i hold a key down for long, it launches this function over and over again rapidly and screws up my rectangle location code.
My theory/logic behind it:
BECAUSE WHEN YOU HOLD A BUTTON DOWN ON A KEYBOARD IT DOES NOT MOVE SMOOTHLY (TEST IT ON THE SCROLL BAR IN YOUR BROWSER, IT STARTS, pauses, THEN CONTINUES SMOOTHLY), i want it to start a forms timer that moves the object in the UI. Then when the KeyUp event happens, the timer STOPS.
public void Window_KeyDown(object sender, KeyEventArgs e)
{
string msg;
string keystr = e.Key.ToString();
Key keyval = e.Key;
switch (keystr)
{
case "Down":
Console.WriteLine("Case 1");
Display.Content = "Down";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Down");
}
break;
case "Up":
Console.WriteLine("Case 2");
Display.Content = "Up";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Up");
}
break;
case "Left":
Console.WriteLine("Case 3");
Display.Content = "Left";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Left");
}
break;
case "Right":
Display.Content = "Right";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Right");
}
break;
}
}
public void Window_KeyUp(object sender, KeyEventArgs e)
{
Display.Content = "No key is pressed.";
foreach (Character character in creatures)
{
if (e.Key == Key.Right)
{
character.StopIt();
}
if (e.Key == Key.Left)
{
character.StopIt();
}
if (e.Key == Key.Up)
{
character.StopIt();
}
if (e.Key == Key.Down)
{
character.StopIt();
}
}
}
and just for reference if you need my rectangle class code i'll post what happens if the RIGHT arrow key is pressed:
Position is called
public void Position(String Direction)
{
if (Direction == "Right")
{
tmr = new System.Windows.Forms.Timer();
tmr.Interval = this.waitTime;
tmr.Tick += new EventHandler(GoRight);
tmr.Start();
}
}
GoRight is called:
public void GoRight(object sender, System.EventArgs e)
{
if (x < Background.ActualWidth - CharacterWidth)
{
if (goRight)
{
x += incrementSize;
CharacterImage.SetValue(Canvas.LeftProperty, x);
}
if (x > Background.ActualWidth - CharacterWidth)
{
goRight = false;
tmr.Stop();
}
}
}
Finally, StopIt is called in the KeyUp event:
public void StopIt()
{
tmr.Stop();
goRight = true;
goLeft = true;
goUp = true;
goDown = true;
}
I've only been learning c# for a couple months now so i'm trying to keep it relatively simple if possible, and only use .net.
Any help would be appreciated!!
EDIT:: MY SOLUTION:
I simply made a while(flag) loop around my switch case. Then i set flag = false within the cases. When Key UP is pressed i set flag equal to true again. YAY
I assume that you want your character to move on the initial KeyDown event. Then you want to ignore any subsequent KeyDown events until you get a KeyUp event.
So you can ignore the subsequent KeyDown events by checking e.IsRepeat e.g.
public void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.IsRepeat) return;
// rest of your code...
BTW, the non-smooth movement that you observe when scrolling an application is caused by the keyboard repeat delay. You can set this in the keyboard properties or though http://msdn.microsoft.com/en-us/library/system.windows.systemparameters.keyboarddelay.aspx
I don't know enough about WPF to tell you what is going on, though you may be correct about the push button/pause thing. It depends on how WPF treats keypresses. My guess would be that it does so the same way most Microsoft forms work; it has a pause to keep you from typing multiple characters at a time. There may be a way around this but I'm not sure.
What I will say though is that you should use something designed for games. When I first tried creating games I did so in a style similar to what you are doing and it doesn't work. What you are using is designed for office software and will not give you access to what you need; at least not without fighting and workarounds. As was suggested by Alex Beisley look into XNA. It's a dead language unfortunately but it died fairly recently. It uses c#, was made by Microsoft, and is powerful enough to do what you want without fighting you and easy enough to use once you get the hang of it. It's a shame to see it killed off.
If you want to torture yourself then I'd suggest going the route I've been trying which is to learn C++ and DirectX. It is not easy and you will need to be patient and go through multiple tutorials (no one tutorial seems to do a good job explaining anything). DirectX and C++ are not going anywhere soon, so they are a safe bet if you are looking to get into a long term language.

Holding Arrow Keys Down For Character Movement C# .Net ISSUES

So in short i'm simply trying to move a rectangle around a Canvas object in a WPF application. What i have here is my KeyDown event function. The problem is, when i hold a key down for long, it launches this function over and over again rapidly and screws up my rectangle location code.
My theory/logic behind it:
BECAUSE WHEN YOU HOLD A BUTTON DOWN ON A KEYBOARD IT DOES NOT MOVE SMOOTHLY (TEST IT ON THE SCROLL BAR IN YOUR BROWSER, IT STARTS, pauses, THEN CONTINUES SMOOTHLY), i want it to start a forms timer that moves the object in the UI. Then when the KeyUp event happens, the timer STOPS.
public void Window_KeyDown(object sender, KeyEventArgs e)
{
string msg;
string keystr = e.Key.ToString();
Key keyval = e.Key;
switch (keystr)
{
case "Down":
Console.WriteLine("Case 1");
Display.Content = "Down";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Down");
}
break;
case "Up":
Console.WriteLine("Case 2");
Display.Content = "Up";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Up");
}
break;
case "Left":
Console.WriteLine("Case 3");
Display.Content = "Left";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Left");
}
break;
case "Right":
Display.Content = "Right";
foreach (Character character in creatures)
{
//character.buttondown = true;
character.Position("Right");
}
break;
}
}
public void Window_KeyUp(object sender, KeyEventArgs e)
{
Display.Content = "No key is pressed.";
foreach (Character character in creatures)
{
if (e.Key == Key.Right)
{
character.StopIt();
}
if (e.Key == Key.Left)
{
character.StopIt();
}
if (e.Key == Key.Up)
{
character.StopIt();
}
if (e.Key == Key.Down)
{
character.StopIt();
}
}
}
and just for reference if you need my rectangle class code i'll post what happens if the RIGHT arrow key is pressed:
Position is called
public void Position(String Direction)
{
if (Direction == "Right")
{
tmr = new System.Windows.Forms.Timer();
tmr.Interval = this.waitTime;
tmr.Tick += new EventHandler(GoRight);
tmr.Start();
}
}
GoRight is called:
public void GoRight(object sender, System.EventArgs e)
{
if (x < Background.ActualWidth - CharacterWidth)
{
if (goRight)
{
x += incrementSize;
CharacterImage.SetValue(Canvas.LeftProperty, x);
}
if (x > Background.ActualWidth - CharacterWidth)
{
goRight = false;
tmr.Stop();
}
}
}
Finally, StopIt is called in the KeyUp event:
public void StopIt()
{
tmr.Stop();
goRight = true;
goLeft = true;
goUp = true;
goDown = true;
}
I've only been learning c# for a couple months now so i'm trying to keep it relatively simple if possible, and only use .net.
Any help would be appreciated!!
EDIT:: MY SOLUTION:
I simply made a while(flag) loop around my switch case. Then i set flag = false within the cases. When Key UP is pressed i set flag equal to true again. YAY
I assume that you want your character to move on the initial KeyDown event. Then you want to ignore any subsequent KeyDown events until you get a KeyUp event.
So you can ignore the subsequent KeyDown events by checking e.IsRepeat e.g.
public void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.IsRepeat) return;
// rest of your code...
BTW, the non-smooth movement that you observe when scrolling an application is caused by the keyboard repeat delay. You can set this in the keyboard properties or though http://msdn.microsoft.com/en-us/library/system.windows.systemparameters.keyboarddelay.aspx
I don't know enough about WPF to tell you what is going on, though you may be correct about the push button/pause thing. It depends on how WPF treats keypresses. My guess would be that it does so the same way most Microsoft forms work; it has a pause to keep you from typing multiple characters at a time. There may be a way around this but I'm not sure.
What I will say though is that you should use something designed for games. When I first tried creating games I did so in a style similar to what you are doing and it doesn't work. What you are using is designed for office software and will not give you access to what you need; at least not without fighting and workarounds. As was suggested by Alex Beisley look into XNA. It's a dead language unfortunately but it died fairly recently. It uses c#, was made by Microsoft, and is powerful enough to do what you want without fighting you and easy enough to use once you get the hang of it. It's a shame to see it killed off.
If you want to torture yourself then I'd suggest going the route I've been trying which is to learn C++ and DirectX. It is not easy and you will need to be patient and go through multiple tutorials (no one tutorial seems to do a good job explaining anything). DirectX and C++ are not going anywhere soon, so they are a safe bet if you are looking to get into a long term language.

Stopping keys from repeating (C#)

In this application, I need to be able to stop the response from a key which is held down in order to prevent unnessecary data from entering the output. The problem I'm having is, using the methods in my code below does prevent the keys from repeating, but it also stops them from being responsive enough - as the users are hitting the keys very quickly.
I'm not sure if it's my hardware, api restriction or a problem with my code, but the routines I have below do not simply come round fast enough to work without making the program impossible to use. A way of identifying if a key is being actively held down (and for how long) would also help another feature for the program and solve this current issue.
Any ideas?
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = isKeyDown;
isKeyDown = true;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
isKeyDown = false;
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!isStreamPlaying) return;
if (e.KeyChar.Equals('d') || e.KeyChar.Equals('j'))
{
//red hit
SoundPlayer hitSounds = new SoundPlayer(taikoLiveMapper.Properties.Resources.normal_hitnormal);
hitSounds.Play();
outputlist.Add(string.Format("320,240,{0},1,{1}", ms, 0));
lastms = ms;
}
else if (e.KeyChar.Equals('s') || e.KeyChar.Equals('k'))
{
//blue hit
SoundPlayer hitSounds = new SoundPlayer(taikoLiveMapper.Properties.Resources.normal_hitclap);
hitSounds.Play();
outputlist.Add(string.Format("320,240,{0},1,{1}", ms, 8));
lastms = ms;
}
}
You can use GetKeyState to find out if a key is down and use that to track the keys:
[DllImport("user32.dll")]
static extern short GetKeyState(int key);
static bool IsKeyPressed(Keys key)
{
short state = GetKeyState((int)key);
return ((state & 128) != 0);
}
int i = 0;
Dictionary<Keys, DateTime> downSince = new Dictionary<Keys, DateTime>();
private void UpdateKeyStates()
{
foreach (var entry in downSince.ToArray())
{
if (!IsKeyPressed(entry.Key))
downSince.Remove(entry.Key);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
UpdateKeyStates();
if (!downSince.ContainsKey(e.KeyCode))
{
downSince.Add(e.KeyCode, DateTime.UtcNow);
i++;
}
Text = i.ToString() + " " +(int)(DateTime.UtcNow - downSince[e.KeyCode]).TotalMilliseconds;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
UpdateKeyStates();
}
This example counts i up every time a key is pressed, and shows for how long it has been pressed. It uses GetKeyState instead of tracking KeyDown/KeyUp since you might miss those messages if something else has focus.
According to the documentation, "[d]uplicate KeyDown events occur each time the key repeats, if the key is held down, but only one KeyUp event is generated when the user releases the key."
So the simplest solution is to ignore a repeated KeyDown event unless its corresponding KeyUp event has been seen.
Just worked for me.
Use Timers instead: initialize timers, one for each "action" (e.g. pressing d/j or s/k) move the red hit/blue hit code inside the timer and instead of your current code, have this:
if (e.KeyChar.Equals('d') || e.KeyChar.Equals('j'))
{
//red hit
if (!tmrRedHit.Enabled)
tmrRedHit.Enabled = true;
}
else if (e.KeyChar.Equals('s') || e.KeyChar.Equals('k'))
{
//blue hit
if (!tmrBlueHit.Enabled)
tmrBlueHit.Enabled = true;
}
And in the timers Elpased event also set their Enabled to false after the code is executed.

Multiple key presses doing different events in C#

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W)
player1.moveUp();
if (e.KeyCode == Keys.NumPad8)
player2.moveUp();
}
In the above code the moveUp methods basically just increment a value. I want it so both keys can be pressed (or held down)at the same time and both events will trigger.
Thanks,
Nevik
Get the state of the keyboard and check for the status of the keys that you want.
Events are not the best way to go in gaming. You need faster response.
[DllImport("user32.dll")]
public static extern int GetKeyboardState(byte [] lpKeyState);
...
byte[] bCharData = new byte[256];
GetKeyboardState(bCharData);
Another way, taken from here,
[DllImport("user32.dll")]
static extern short GetKeyState(VirtualKeyStates nVirtKey);
...
public static bool IsKeyPressed(VirtualKeyStates testKey)
{
bool keyPressed = false;
short result= GetKeyState(testKey);
switch (result)
{
case 0:
// Not pressed and not toggled on.
keyPressed = false;
break;
case 1:
// Not pressed, but toggled on
keyPressed = false;
break;
default:
// Pressed (and may be toggled on)
keyPressed = true;
break;
}
return keyPressed;
}
More links.
Basically, these are already available on net. Try searching before asking. It will be faster :)
Let's assume you have a "game loop" that updates the object you're moving with the keyboard. The KeyDown event should change the object state to "moving upwards". And your loop then gives it new positions each time it runs.
The KeyUp event should change the state back to "idle". Iff the state is still "moving upwards".
You now no longer depend on a keystroke repeating to keep the object moving. And will have no trouble with the player pressing multiple keys at the same time.

Hotkeys override

Difficult question. The answer is probably no, if all I found in the Intertubes is right, but it is worth a try. I need to override the Ctrl + Shift + Esc and the Ctrl + Esc combinations. It would be good to be able to override the Win key combinations, but I have a low level hook that does such, I only wish I didn't need it. If I can manage to block the start menu and the task manager entirely by policy, the overrides will no longer be needed but I couldn't find the correct policy to do so.
You can override Ctrl + Esc (I just tried in AutoHotkey, it works), but not Ctrl + Shift + Esc, no more than Ctrl + Alt + Del.
So using policies is probably the way to go... No experience in this field, I fear.
In case someone comes here looking for a non-AutoHotKey, here is a c# way.
It is possible to do this using a keyboard hook. A good hook class for this can be found on this CodeProject Article
Using the below code will prevent the WIN+LEFT or WIN+RIGHT from occurring. You can use this to override whichever keys you'd like.
This will even override hotkeys which you added via RegisterHotKey Win API.
Once you have those classes in your project you can add handlers to the static HookManager class like below.
//It's worth noting here that if you subscribe to the Key_Press event then it will break the international accent keys.
HookManager.KeyPress += HookManager_KeyPress;
HookManager.KeyDown += HookManager_KeyDown;
HookManager.KeyUp += HookManager_KeyUp;
You can also add mouse events, but for simplicity I'm just showing the keyboard hook.
I've also created a generic list so that I know which keys are currently down and I remove those keys from the list on the KeyUp event.
public static List<Keys> keysDown = new List<Keys>();
private static void HookManager_KeyDown(object sender, KeyEventArgs e)
{
//Used for overriding the Windows default hotkeys
if(keysDown.Contains(e.KeyCode) == false)
{
keysDown.Add(e.KeyCode);
}
if (e.KeyCode == Keys.Right && WIN())
{
e.Handled = true;
//Do what you want when this key combination is pressed
}
else if (e.KeyCode == Keys.Left && WIN())
{
e.Handled = true;
//Do what you want when this key combination is pressed
}
}
private static void HookManager_KeyUp(object sender, KeyEventArgs e)
{
//Used for overriding the Windows default hotkeys
while(keysDown.Contains(e.KeyCode))
{
keysDown.Remove(e.KeyCode);
}
}
private static void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
//Used for overriding the Windows default hotkeys
}
public static bool CTRL()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.LControlKey) ||
keysDown.Contains(Keys.RControlKey) ||
keysDown.Contains(Keys.Control) ||
keysDown.Contains(Keys.ControlKey))
{
return true;
}
else
{
return false;
}
}
public static bool SHIFT()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.LShiftKey) ||
keysDown.Contains(Keys.RShiftKey) ||
keysDown.Contains(Keys.Shift) ||
keysDown.Contains(Keys.ShiftKey))
{
return true;
}
else
{
return false;
}
}
public static bool WIN()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.LWin) ||
keysDown.Contains(Keys.RWin))
{
return true;
}
else
{
return false;
}
}
public static bool ALT()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.Alt))
{
return true;
}
else
{
return false;
}
}
So you need do override Hotkeys on your application?
Then the answer is probably yes, how?
No idea, but if this(http://www.inchwest.com/mapkeyboard.aspx) program can, so can you

Categories

Resources