Преобразование строки или символа в объект Keys

Если я использую следующий код:

for (int i = 0; i < text.Length; i++)
    {
        char c = text[i];
        Keys k = (Keys)(byte)c;
        MessageBox.Show(c.ToString() + "|" + k.ToString());
    }

Я могу получить правильное преобразование только для заглавных букв. Проблема в том, что мне нужно иметь возможность копировать символы нижнего регистра, и я получаю для них ошибки преобразования. Например, «e» преобразуется в «NumPad5», где «E» правильно преобразуется в «E». Как мне атаковать это? Я собираюсь брать входные строки и создавать виртуальные нажатия клавиш для макроплеера, который я пытаюсь разработать.


person ashurexm    schedule 18.10.2010    source источник
comment
Вы можете сделать text.ToUpper()[i] вместо text[i] или... Keys key = ( c ›= 'a' && c ‹= 'z' ) ? (Ключи.A + c - 'a') : (Ключи)c;   -  person Kit10    schedule 19.10.2012


Ответы (3)


Это похоже на неправильный подход. Рассматривали ли вы возможность использования SendKeys?

person Jonathan    schedule 18.10.2010
comment
Я бы дал вам +1 миллион, если бы мог. Это НАМНОГО проще, чем я думал. Я только что использовал SendKeys.SendWait(text);, и он действовал именно так, как я хотел! - person ashurexm; 19.10.2010
comment
SendKeys генерирует исключение, если целевое окно не обрабатывает команды WM. - person Kit10; 19.10.2012

Перечисление Keys не является прямой копией значений символа, сгенерированного при нажатии клавиши. Иногда это так, но иногда это не так. Способ кодирования значения для каждого нажатия клавиши описан в документация:

Этот класс содержит константы для обработки ввода с клавиатуры. Ключи идентифицируются значениями ключей, которые состоят из кода ключа и набора модификаторов, объединенных в одно целочисленное значение. Четыре левые цифры значения ключа содержат код ключа (который совпадает с кодом виртуального ключа Windows). Четыре правые цифры значения ключа содержат биты-модификаторы для клавиш SHIFT, CONTROL и ALT.

person Mark Byers    schedule 18.10.2010

Ответ состоит в том, чтобы создать таблицу обратного поиска для нужных вам символов. Код можно было бы еще оптимизировать, но он не требует пояснений. При необходимости вы можете явно добавить специальные символы.

Вы также можете одновременно создать словарь, чтобы пойти другим путем, если вам это понравится. Многоключевые символы потребуют тривиального расширения, но в любом случае они не сопоставляются напрямую с ключами. Для ознакомления и возможного расширения, если оно вам потребуется:

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);
person Shane Paul    schedule 21.06.2017
comment
Это то, что я искал. Удивительная вещь, спасибо, я посмотрю. - person AgentFire; 22.06.2017
comment
НП. Это fugly как ад, но работает хорошо. Не предполагая, что это лучшая идея для большинства приложений, но мне надоело видеть, как люди говорят, что это невозможно, и это помечается как правильный ответ. Я думаю, если вы не знаете, как утешительно думать, что это невозможно? - person Shane Paul; 23.06.2017