问题
If I use the following code:
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
Keys k = (Keys)(byte)c;
MessageBox.Show(c.ToString() + "|" + k.ToString());
}
I can get a correct conversion for uppercase letters only. The problem is, I need to be able to replicate lower case characters as well, and I am getting conversion errors on them. For instance, 'e' converts to 'NumPad5', where 'E' converts correctly to 'E'. How do I attack this? I'm going to be taking input strings and creating virtual key presses for a macro player I am trying to develop.
回答1:
That seems like the wrong approach. Have you considered using SendKeys?
回答2:
The Keys
enumeration is not a straight copy of the character values of the character generated when the key is pressed. Sometimes it is, but sometimes it is not. The way the value is encoded for each keypress is described in the documentation:
This class contains constants to use for processing keyboard input. Keys are identified by key values, which consist of a key code and a set of modifiers combined into a single integer value. The four left digits of a key value contain the key code (which is the same as a Windows virtual key code). The four right digits of a key value contain modifier bits for the SHIFT, CONTROL, and ALT keys.
回答3:
The answer is to build a reverse lookup table for the chars you need. The code could be optimized further but it is self explanatory. You could add special chars explicitly if needed.
You could also simultaneously build a dictionary to go the other way also should it take your fancy. Multi-key chars would require a trivial extension but they don't map directly to Keys anyway. For your perusal and possible extension should you require it:
using System.Windows.Forms;
static ImmutableDictionary<char, Keys> CharVKeyLookup;
static void PopulateVKeyCharDictionary(){
var keyboardStateNormal = new byte[255]; //All keys up
var keyboardStateShift = new byte[255];
keyboardStateShift[(int)Keys.ShiftKey] = 0x80;
var charlookup = new Dictionary<char, Keys>();
for (var i = 1; i < (int) Keys.OemClear; i++){
var keys = (Keys) i;
//Verbose condition to ignore unnecessary conversions - probably a quicker way e.g. statically
if (keys == Keys.Enter || keys == Keys.Tab || keys == Keys.Space
|| (keys >= Keys.D0 && keys <= Keys.D9)
|| (keys >= Keys.A && keys <= Keys.Z)
|| (keys >= Keys.Multiply && keys <= Keys.Divide)
|| (keys >= Keys.Oem1 && keys <= Keys.Oem102)){
var normal = KeyCodeToUnicode(keys);
var shift = KeyCodeToUnicode(keys, true);
if (normal.Item2 == 1) //Ignore wierdos - extend this if you need it
charlookup[normal.Item1[0]]=keys;
if (shift.Item2 ==1)
charlookup[shift.Item1[0]]=keys|Keys.Shift; //Incl shift mod
}
}
charlookup['\n'] = Keys.Return;
charlookup['\r'] = Keys.Return;
CharVKeyLookup = charlookup.ToImmutableDictionary();
}
/// <returns>string if it exists and return code. -1=dead char, 0=no translation, 1=1 char, 2=special char </returns>
public static Tuple<string, int> KeyCodeToUnicode(Keys key, byte[] keyboardState){
var scanCode = MapVKToScanCode(key);
var result = new StringBuilder(10,10);
var language = InputLanguage.CurrentInputLanguage.Handle;//Or other method such as GetKeyboardLayout
var returnState = ToUnicodeEx(key, scanCode, keyboardState, result, 10, 0, language);
return new Tuple<string, int>(result.ToString(),returnState);
}
[DllImport("user32.dll")]
internal static extern int ToUnicodeEx(Keys wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr GetKeyboardLayout(int dwLayout);
来源:https://stackoverflow.com/questions/3962944/convert-string-or-char-to-keys-object