How to adapt WPF KeyEventArgs to Winforms KeyEventArgs? [duplicate] - c#

I'm developing application in WPF but some components are written using WinForms. I wan't these components to pull key gesture from WPF part and convert them to Keys enum (used in WinForms).
Is there a built in converter for that? (probably not)
Do you know "easier than big switch case" method to do that?

Keys formsKey = ...;
Key wpfKey = ...;
wpfKey = KeyInterop.KeyFromVirtualKey((int)formsKey);
formsKey = (Keys)KeyInterop.VirtualKeyFromKey(wpfKey);
The KeyInterop class is the "key," plus the fact that the Windows Forms Keys enumeration has the same integer values as the Win 32 virtual key codes.

Just in case people still encounter the modifier problem 7 years later, here's my solution that worked so far :
public static class KeyEventExts
{
public static System.Windows.Forms.KeyEventArgs ToWinforms(this System.Windows.Input.KeyEventArgs keyEventArgs)
{
// So far this ternary remained pointless, might be useful in some very specific cases though
var wpfKey = keyEventArgs.Key == System.Windows.Input.Key.System ? keyEventArgs.SystemKey : keyEventArgs.Key;
var winformModifiers = keyEventArgs.KeyboardDevice.Modifiers.ToWinforms();
var winformKeys = (System.Windows.Forms.Keys)System.Windows.Input.KeyInterop.VirtualKeyFromKey(wpfKey);
return new System.Windows.Forms.KeyEventArgs(winformKeys | winformModifiers);
}
public static System.Windows.Forms.Keys ToWinforms(this System.Windows.Input.ModifierKeys modifier)
{
var retVal = System.Windows.Forms.Keys.None;
if(modifier.HasFlag(System.Windows.Input.ModifierKeys.Alt))
{
retVal |= System.Windows.Forms.Keys.Alt;
}
if (modifier.HasFlag(System.Windows.Input.ModifierKeys.Control))
{
retVal |= System.Windows.Forms.Keys.Control;
}
if (modifier.HasFlag(System.Windows.Input.ModifierKeys.None))
{
// Pointless I know
retVal |= System.Windows.Forms.Keys.None;
}
if (modifier.HasFlag(System.Windows.Input.ModifierKeys.Shift))
{
retVal |= System.Windows.Forms.Keys.Shift;
}
if (modifier.HasFlag(System.Windows.Input.ModifierKeys.Windows))
{
// Not supported lel
}
return retVal;
}
}

If you want to convert modifiers, use the SystemKey if you're looking at a KeyEventArgs:
System.Windows.Input.KeyEventArgs args;
System.Windows.Input.Key wpfKey= args.Key == Key.System ? args.SystemKey : args.Key;
formsKey = (System.Windows.Forms.Keys)KeyInterop.VirtualKeyFromKey(wpfKey);

To convert the WPF Key enumeration to the corresponding WinForms Keys enumeration use the static member TryParse of the Enum class:
Enum.TryParse(wpfKeyEnum.ToString(), out System.Windows.Forms.Keys winFormsKeyEnum)
WPF modifiers (ModifierKeys enumeration) can be converted the same way except the Windows key. In contrast to the Windows.Input.ModifierKeys enumeration of WPF the Windows.Forms.Keys enumeration distinguishes between left and right Windows keys and defines corresponding LWin an RWin fields.
This conversion method works in both directions.
Example
The example converts the Key and ModifierKeys enumerations of a WPF key up event to the corresponding WinForms Keys enumeration.
From Windows.Input.Key To System.Windows.Forms.Keys
private void OnPreviewKeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
// Convert key
if (Enum.TryParse(e.Key.ToString(), out System.Windows.Forms.Keys winFormsKey))
{
MessageBox.Show(winFormsKey + "=" + (int) winFormsKey); // A=65
}
}
From Windows.Input.ModifierKeys To System.Windows.Forms.Keys
private void OnPreviewKeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
ModifierKeys modifiers = e.KeyboardDevice.Modifiers;
IEnumerable<ModifierKeys> pressedModifierKeys = Enum.GetValues(modifiers.GetType())
.Cast<ModifierKeys>()
.Where(modifiers.HasFlag);
// The ModifierKeys enumeration has a FlagsAttribute attribute
foreach (ModifierKeys modifier in pressedModifierKeys)
{
if (Enum.TryParse(modifier.ToString(), out System.Windows.Forms.Keys winFormsModifierKey))
{
MessageBox.Show(winFormsModifierKey + "=" + (int) winFormsModifierKey); // Alt=262144
}
}
}

Related

How could i recognize 2 separate key presses as one key?

So for a game i'm working i have a bunch of different keys doing different things (for example w key makes the player look up and the e key makes the character look up right).
I'm wondering is there a way to make the W + the D key make the player look up right, even though those keys are already being used.
private void FrmGM_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W)
{
picplayer.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.IPT_game_player1));
bulletnumb = 1;
}
if (e.KeyCode == Keys.E)
{
picplayer.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.IPT_game_player2));
bulletnumb = 2;
}
if (e.KeyCode == Keys.D)
{
picplayer.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.IPT_game_player3));
bulletnumb = 3;
}
if (e.KeyCode == Keys.C)
{
picplayer.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.IPT_game_player4));
bulletnumb = 4;
}
if (e.KeyCode == Keys.X)
{
picplayer.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.IPT_game_player5));
bulletnumb = 5;
}
if (e.KeyCode == Keys.Z)
{
picplayer.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.IPT_game_player6));
bulletnumb = 6;
}
if (e.KeyCode == Keys.A)
{
picplayer.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.IPT_game_player7));
bulletnumb = 7;
}
if (e.KeyCode == Keys.Q)
{
picplayer.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.IPT_game_player8));
bulletnumb = 8;
}
this is the code for my keys presses
Store letters in a set when the KeyDown events arrive, and remove them in the KeyUp event handler. This way your KeyDown would be able to "see" if the "companion key" has been pressed:
private readonly ISet<char> keysCurrentlyDown = new HashSet<char>();
private void FrmGM_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.W)
{
if (keysCurrentlyDown.Contains('D')) {
// Call some method to handle W+D
} else {
...
}
keysCurrentlyDown.Add('W');
} else if (e.KeyCode == Keys.D)
{
if (keysCurrentlyDown.Contains('W')) {
// Call some method to handle W+D
} else {
...
}
keysCurrentlyDown.Add('D');
}
...
}
private void FrmGM_KeyUp(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.W) {
keysCurrentlyDown.Remove('W');
} else if (e.KeyCode == Keys.D) {
keysCurrentlyDown.Remove('D');
} ...
}
}
The first line of offense for this sort of thing is just to make sure that each key can be activated concurrently, and that the combination of the effects of each key have the result you want. Your code will be more maintainable and easier to write if you follow that approach, rather than trying to special-case the combine key input.
For example, you can have a set of flags that represent the current key state, and then on your game's frame update, check those flags and set the character state to the correct thing (i.e. instead of setting specific images in the key-handling itself, as you're doing now).
So you could have flags like:
bool lookUp, lookRight, lookDown, lookLeft;
Then key-down for W would set the lookUp flag, while key-up for the same key would clear the flag. Likewise e.g. for D, for the lookRight flag.
Then on your game frame update, you check the flags. If lookUp and lookRight are both set, then you use the "look up and right" graphic. If just one or the other flag are set, then you use the plain "look up" or "look right" graphic. Likewise for other keys and their combinations. You could even resolve lookUp and lookDown, or lookLeft and lookRight, as whatever the default graphic would be (i.e. as if the user pressed no keys).
Note that if you're willing to use p/invoke, you can use the GetAsyncKeyState() function, and not even bother with the key-down event. Just check the key state before each frame update for the game, and update the visuals according to the current keyboard state. That way, you let Windows do all the key state tracking, and you don't waste time tracking key state that doesn't matter (e.g. if the user causes multiple changes to the key state between frames).
That said, if you can't/won't do any of the above, then yes...all you need to do is check for the combination first (i.e. you got the key-down for both, without a key-up for the initially-pressed key of the combination).
Do note that taking that approach means that you will still take the effect for the first key pressed, and then have to switch to the combination effect.
use the
PresentationCore.dll and the
WindowsBase.dll as reference in your project
PresentationCore.dll has a Keyboard - Class and WindowsBase.dll has a Key - Class.
then:
using System;
using System.Windows.Forms;
using System.Windows.Input;
namespace ViewTest
{
public partial class ViewTest : Form
{
private void ViewTest_KeyDown(object sender, KeyEventArgs e)
{
if (Keyboard.IsKeyDown(System.Windows.Input.Key.W) &&
Keyboard.IsKeyDown(System.Windows.Input.Key.D))
{
// do something
}
}
}
it's a simple way to do this :)
Look into overriding the ProcessCmdKey
protected override bool ProcessCmdKey(ref Message m, Keys k)
{
if (k == (Keys.Control | Keys.D))
{
MessageBox.Show("CTRL+D");
return true;
}
return base.ProcessCmdKey(ref m, k);
}

How to convert a VirtualKey to a char for non-US keyboard layouts in WinRT?

In standard .NET there existed the ToAscii/ToUnicode and MapVirtualKey functions to take care of this functionality, though it seems an equivalent function or library has not been brought into Metro/WinRT. If there is actually no equivalent function or library exposed in Metro/WinRT then that would make a custom text input box VERY difficult to bring to market in non-US countries.
Specific example: in my custom control, if a french keyboard user presses the è,ù,é, or à keys, they are unable to be translated to the correct character. For example, è uses the scan code for VirtualKey.Number7, and as far as I can tell there is no way to know the keyboard layout or no easy way to translate that scancode based on the current keyboard layout.
Does anyone have some information about this?
I suppose it depends on what you are looking for. If you are looking for a simple English letter or number, you can simply do this:
private static char? ToChar(VirtualKey key, bool shift)
{
// convert virtual key to char
if (32 == (int)key)
return ' ';
VirtualKey search;
// look for simple letter
foreach (var letter in "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
{
if (Enum.TryParse<VirtualKey>(letter.ToString(), out search) && search.Equals(key))
return (shift) ? letter : letter.ToString().ToLower()[0];
}
// look for simple number
foreach (var number in "1234567890")
{
if (Enum.TryParse<VirtualKey>("Number" + number.ToString(), out search) && search.Equals(key))
return number;
}
// not found
return null;
}
Best of luck!
For WinRT (example with a TextBox and only select Letters):
CoreWindow.GetForCurrentThread().CharacterReceived += TextBox_CharacterReceived;
void TextBox_CharacterReceived(CoreWindow sender, CharacterReceivedEventArgs args)
{
char c = Convert.ToChar(args.KeyCode);
if (char.IsLetter(c))
{
...
}
}
For cancel de char entry:
TextBox textBoxData;
void TextBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
textBoxData = sender as TextBox;
if (e.Key!=VirtualKey.Space)
e.Handled = true;
}
optional:
void TextBox_Paste(object sender, TextControlPasteEventArgs e)
{
e.Handled = true;
}
and modify CharacterReceived:
if (char.IsLetter(c))
{
textBoxData.Text += c;
textBoxData.SelectionStart = textBoxData.Text.Length;
}
Warning! if your TextBox has a MaxLength you must modify your code:
if (char.IsLetter(c) && textBoxData.Text.Length < textBoxData.MaxLength)
You can use the Win32 API function MapVirtualKey that maps a virtual key to a bunch of values one of which is a character value. MapVirtualKey seems to use the currently set keyboard layout (this is not documented). To use a specified layout you could use MapVirtualKeyEx.
MapVirtualKey does not take into account whether Shift is pressed or not. To easily get an information if Shift is pressed you could use GetKeyState (unfortunately the WinRT team didn't make it easy to get the state of the modifier keys).
Here is an example of how to translate a virtual key into a character:
[DllImport("user32.dll")]
private static extern uint MapVirtualKey(uint uCode, uint uMapType);
[DllImport("user32.dll")]
private static extern short GetKeyState(uint nVirtKey);
private const uint MAPVK_VK_TO_CHAR = 0x02;
private const uint VK_SHIFT = 0x10;
private char TranslateVirtualKeyIntoChar(VirtualKey key)
{
char c = (char)MapVirtualKey((uint)key, MAPVK_VK_TO_CHAR);
short shiftState = GetKeyState(VK_SHIFT);
if (shiftState < 0)
{
// Shift is pressed
c = char.ToUpper(c);
}
return c;
}
Update
Unfortunately this solution is not applicable for Windows Store Apps that must be certified. The certification fails since with MapVirtualKey and GetKeyState unsupported APIs are used. This means also that this solution will much likely not run under WinRT.

KeyEventArgs to VirtualKeyCode

I'm trying to make use of the WindowsInputSimulator library to help me simulate keyPresses.
The software will consist of a client and a server. When a key is entered on the Client, it's KeyEventArgs are sent to the Server. The server then does the following with it:
public void SendKeyDown(Keys keyCode, Keys modifiers)
{
uint nonVK = MapVirtualKey((uint)keyCode, 2);
char mappedChar = Convert.ToChar(nonVK);
if (modifiers.Equals(Keys.None))
{
VirtualKeyCode vkc;
if (Enum.TryParse(VkKeyScan(mappedChar).ToString(), out vkc))
{
InputSimulator.SimulateKeyDown(vkc);
}
}
else
{
//Find out which modifier we're working with.
uint modVK = MapVirtualKey((uint)modifiers, 2);
char modifierChar = Convert.ToChar(modVK);
VirtualKeyCode vkc, modVkc;
if (Enum.TryParse(VkKeyScan(mappedChar).ToString(), out vkc)
&& Enum.TryParse(VkKeyScan(modifierChar).ToString(), out modVkc))
{
InputSimulator.SimulateModifiedKeyStroke(modVkc, vkc);
}
}
}
Which works for single keys. However, I'm trying to work with modifier keys as well, and I'm running in to some trouble. For example, pressing SHIFT + K produces "k2" Which leads me to believe either my transation into VirtualKeyCodes is wonky, or something else is.
Also, when sending these commands, should I catch only the KeyDown / KeyUp events? Or should I also watch for the KeyPress event? I should be able to wrok with arrow keys and non-Character keys as well, which makes me think I should just ignore the KeyPress.
EDIT: Also, how would I know when I'm working with multiple modifiers? How should I be stringing them together?
Thoughts? Thanks!
I was able to get it working with the following. Keep in mind this works for a SINGLE modifier, and a single CHARACTER. Special characters don't yet work with this code, but I figure it's a step in the right direction, and answered my immediate question.
public void SendKey(int keyValue, Keys modifiers)
{
VirtualKeyCode key;
if (modifiers.Equals(Keys.None))
{
if (Enum.TryParse(VkKeyScan(((char)keyValue)).ToString(), out key))
{
InputSimulator.SimulateKeyDown(key);
InputSimulator.SimulateKeyUp(key);
}
}
else if (modifiers.Equals(Keys.Shift) && keyValue >= (int)Keys.A && keyValue <= (int)Keys.Z)
{
if (Enum.TryParse(VkKeyScan(((char) keyValue)).ToString(), out key))
{
InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.SHIFT, key);
}
}
else if (modifiers.Equals(Keys.Control) && keyValue >= (int)Keys.A && keyValue <= (int)Keys.Z)
{
if (Enum.TryParse(VkKeyScan(((char)keyValue)).ToString(), out key))
{
InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.CONTROL, key);
}
}
else if (modifiers.Equals(Keys.Alt) && keyValue >= (int)Keys.A && keyValue <= (int)Keys.Z)
{
if (Enum.TryParse(VkKeyScan(((char)keyValue)).ToString(), out key))
{
//Alt is named MENU for legacy purposes.
InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.MENU, key);
}
}
}

Capturing Ctrl + Shift + P key stroke in a C# Windows Forms application [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Capture combination key event in a Windows Forms application
I need to perform a particular operation when (Ctrl + Shift + P) keys are pressed.
How can I capture this in my C# application?
Personally I think this is the simplest way.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.Shift && e.KeyCode == Keys.P)
{
MessageBox.Show("Hello");
}
}
The following is not only a way to capture keystroke on your form, but it is in fact a way to add global Windows shortcuts.
1. Import needed libraries at the top of your class:
// DLL libraries used to manage hotkeys
[DllImport("user32.dll")] public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")] public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
2. Add a field in your Windows Forms class that will be a reference for the hotkey in your code:
const int MYACTION_HOTKEY_ID = 1;
3. Register the hotkey (in the constructor of your Windows Forms for instance):
// Modifier keys codes: Alt = 1, Ctrl = 2, Shift = 4, Win = 8
// Compute the addition of each combination of the keys you want to be pressed
// ALT+CTRL = 1 + 2 = 3 , CTRL+SHIFT = 2 + 4 = 6...
RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 6, (int)'P');
4. Handle the typed keys by adding the following method in your Windows Forms class:
protected override void WndProc(ref Message m) {
if (m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID) {
// My hotkey has been typed
// Do what you want here
// ...
}
base.WndProc(ref m);
}
You can use the KeyDownEvent with a lambda event handler:
Here is some more information about KeyDown. Read the article and think about the scope in which you want to have this behavior.
this.KeyDown += (object sender, KeyEventArgs e) =>
{
if (e.Control && e.Shift && e.KeyCode == Keys.P)
{
MessageBox.Show("pressed");
}
};
Use the GetKeyboardState API via P/Invoke. It returns an array representing the state of each virtual key recognised by Windows. If I'm not mistaken, you can cast the Keys enum to a byte and use it as an index as follows:
byte[] keys = new byte[256];
GetKeyboardState(keys);
bool isCtrlPressed = (keys[(byte)Keys.ControlKey] == 1);
-
Resources:
P/Invoke definition
MSDN documentation: GetKeyboardState function

Is there any C# implementation or way to have a textbox that takes a key sequence as input?

I have an implementation which hooks into the keydown event, which suppresses the keypress event and does some magic. Now I want to show something more friendly than "ControlKey" etc, so there's a switch you can see in the code below. Except I've realised things like the number keys along the top end up as D1, D2, etc., and then there's things like Add showing up for the numpad +. In addition, Print Screen doesn't seem to be recognised.
Is there something I'm missing?
This is a hard question for me to describe fluently, but hopefully you get what I mean. If not I guess I'll be replying to comments and improving this as I go.
private int numKeys = 0;
private List<int> shortcutKeys = new List<int>();
private void textBoxRegionKeys_Click(object sender, EventArgs e)
{
textBoxRegionKeys.SelectAll();
}
private void textBoxRegionKeys_KeyDown(object sender, KeyEventArgs e)
{
// There are certain keys we want to ignore...
if (e.KeyCode != Keys.Delete && e.KeyCode != Keys.Back)
{
// We can handle this ourselves, thanks
e.SuppressKeyPress = true;
// Shortern what we show
string ret = e.KeyCode.ToString();
switch (ret)
{
case "ControlKey": ret = "Ctrl"; break;
case "ShiftKey": ret = "Shift"; break;
case "Menu": ret = "Alt"; break;
}
// If we haven't selected anything, we should be appending
if (textBoxRegionKeys.SelectionLength == 0)
{
if (numKeys > 0)
{
// Does our key already exist in the list?
if (shortcutKeys.Exists(x => x == e.KeyValue))
{
return;
}
textBoxRegionKeys.Text += " + ";
}
textBoxRegionKeys.Text += ret;
shortcutKeys.Add(e.KeyValue);
numKeys++;
}
else
{
textBoxRegionKeys.Text = ret;
shortcutKeys.Clear();
shortcutKeys.Add(e.KeyValue);
numKeys = 1;
}
}
}
The TextBox KeyDown/KeyPress etc will only be raised for keys that may be accepted as input in to the text box (and associated modifiers). As such, you will not see keys handled such as Print Screen etc. The best option I can think of is not ideal, but you could override the ProcessKeyPreview or some other Form level Message interceptor to get notified of ANY key press. Something like...
protected override bool ProcessKeyPreview(ref Message m)
{
var keyCode = (Keys)Enum.ToObject(typeof (Keys), m.WParam);
//Insert some logic
return base.ProcessKeyPreview(ref m);
}
Of course, this method will be invoked whenever the FORM has focus, and a key is pressed, so you would have to filter down by doing some form of check (which again is not ideal)
if(ReferenceEquals(ActiveControl, textBoxRegionKeys)) {}
Which if your dealing with things like UserControls will be very unreliable.
As for formatting in to nice friendly messages, I think you basically you will need your own map of special characters... I am not aware of any Globalized lookup for Keys. I will dig a little and update the answer if I find something.
Edit
Did a little digging and couldn't find anything obvious for nice key mappings. I would just create a map of "friendly" key names:
private static readonly Dictionary<Keys, String> KeysMap = new Dictionary<Keys, String>
{
{ Keys.D1, "1"},
{ Keys.D9, "9"}
};
And do something like:
String friendlyKeyCode;
if (!KeysMap.TryGetValue(keyCode, out friendlyKeyCode))
friendlyKeyCode = keyCode.ToString();
Personally, I find this approach better than a massive switch... but that works too.

Categories