问题
I want to translate a given set of System.Windows.Forms.Keys
and a System.Windows.Forms.InputLanguage
to the corresponding System.Char
.
Tried some experiments with MapVirtualKeyEx, but there is now way to consider keyboard state, and ToUnicodeEx is a pain with dead keys.
My goal is a function ...
static char? FromKeys(Keys keys, InputLanguage inputLanguage)
{
// As I think what can be helpful and I got trying to find a solution for this problem:
Keys vkCode = keys & Keys.KeyCode;
Keys modifiers = keys & Keys.Modifiers;
byte[] keyboardState = new byte[256];
keyboardState[vkCode] = 1 << 7;
if (modifiers.HasFlag(Keys.Shift))
{
keyboardState[(int)Keys.ShiftKey] = 1 << 7;
}
if (modifiers.HasFlag(Keys.Control))
{
keyboardState[(int)Keys.ControlKey] = 1 << 7;
}
if (modifiers.HasFlag(Keys.Alt))
{
keyboardState[(int)Keys.Menu] = 1 << 7;
}
// [Put your code here]
}
... which should be called like this:
FromKeys(Keys.A | Keys.Shift, InputLanguage.CurrentInputLanguage); // = 'A'
FromKeys(Keys.Escape, InputLanguage.DefaultInputLanguage); // = null
FromKeys(Keys.Oemtilde, InputLanguage.FromCulture(new CultureInfo("de-DE"))); // = 'ö'
FromKeys(Keys.E | Keys.Control | Keys.Alt, InputLanguage.FromCulture(new CultureInfo("de-DE"))); // = '€'
(Be aware of Keys.Shift
and Keys.ShiftKey
!)
How would this function look like?
The answer I'll choose should provide a way to translate one "normal" System.Windows.Forms.Keys
with an optional combination of the modifiers (Keys.Shift
, Keys.Alt
, Keys.Control
) to a System.Char
. Multiple successively calls have to result in the same character. No hardcoded keyboard layouts, the InputLanguage
defines the layout to use.
As a help to understand what I'm trying to to: Generate a KeyPressEventArgs
with just the KeyEventArgs
(and the correct InputLangauge
) given.
Dead keys should not affect FromKeys
!
回答1:
Here is a piece of code that seems to do what you're looking for - if I understood it correctly :-)
public static char? FromKeys(Keys keys, InputLanguage inputLanguage)
{
return FromKeys(keys, inputLanguage, true);
}
private static char? FromKeys(Keys keys, InputLanguage inputLanguage, bool firstChance)
{
if (inputLanguage == null)
{
inputLanguage = InputLanguage.CurrentInputLanguage;
}
byte[] keyStates = new byte[256];
const byte keyPressed = 0x80;
keyStates[(int)(keys & Keys.KeyCode)] = keyPressed;
keyStates[(int)Keys.ShiftKey] = ((keys & Keys.Shift) == Keys.Shift) ? keyPressed : (byte)0;
keyStates[(int)Keys.ControlKey] = ((keys & Keys.Control) == Keys.Control) ? keyPressed : (byte)0;
keyStates[(int)Keys.Menu] = ((keys & Keys.Alt) == Keys.Alt) ? keyPressed : (byte)0;
StringBuilder sb = new StringBuilder(10);
int ret = ToUnicodeEx(keys, 0, keyStates, sb, sb.Capacity, 0, inputLanguage.Handle);
if (ret == 1)
return sb[0];
if (ret == -1)
{
// dead letter
if (firstChance)
{
FromKeys(keys, inputLanguage, false);
}
return null;
}
return null;
}
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int ToUnicodeEx(Keys wVirtKey, uint wScanCode, byte[] lpKeyState, StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);
回答2:
I'm not certain this will work, but you might take a look at ToUnicodeEx. It lets you set the keyboard state as well as the input locale.
Another possibility, although pretty involved, would be to turn your events into strings that are compatible with SendKeys, and then send the string to your application.
You'd have to set the culture for the main thread and use a separate thread to do the sending.
I don't know how well something like that would work, and it's kind of expensive (in terms of time) to try it.
来源:https://stackoverflow.com/questions/6214326/translate-keys-to-char