Преобразуйте расширенные символы ASCII в правильное представление, используя метод Console.ReadKey () и переменную ConsoleKeyInfo - PullRequest
2 голосов
/ 31 марта 2012

Читается около 30 минут, и не нашел какой-то конкретной информации об этом на этом сайте.

Предположим, что в C # консольное приложение:

ConsoleKeyInfo cki;
cki = Console.ReadKey(true);
Console.WriteLine(cki.KeyChar.ToString()); //Or Console.WriteLine(cki.KeyChar) as well
Console.ReadKey(true);

Теперь давайте поместим¿ в записи консоли и присвойте ему значение cki через Console.ReadKey(true).То, что будет показано, это не символ ¿, а символ ¨, который показан вместо этого.И то же самое происходит со многими другими персонажами.Примеры: ñ показывает ¤, ¡ показывает -, ´ показывает ï.

Теперь давайте возьмем тот же фрагмент кода и добавим некоторые вещи для более Console.ReadLine()как поведение:

string data = string.Empty;
ConsoleKeyInfo cki;
for (int i = 0; i < 10; i++)
{
    cki = Console.ReadKey(true);
    data += cki.KeyChar;
}
Console.WriteLine(data);
Console.ReadKey(true);

Вопрос, как правильно это сделать, закончить печать правильных символов, которые должны храниться в data, а не в таких вещах, как ¨, ¤, -, ï и т. Д.

Обратите внимание, что я хочу решение, которое работает с ConsoleKeyInfo и Console.ReadKey(), не использует другие типы переменных или методы чтения.

EDIT:

Поскольку метод ReadKey (), который поступает из пространства имен консоли, зависит от Kernel32.dll, и он определенно плохо обрабатывает расширенный ASCII и Unicode, больше нет возможности просто найти действительное преобразование для того, что он возвращает.

Единственный допустимый способ справиться с плохим поведением ReadKey () - это использовать свойство cki.Key, которое написано в исполнении cki = Console.ReadKey(true), и применить к нему переключатель, а затем вернуть правильные значения в зависимостикакой клавиши была нажата.

Fили, например, для обработки нажатия клавиши Ñ:

string data = string.Empty;
ConsoleKeyInfo cki;
cki = Console.ReadKey(true);
switch (cki.Key)
{
    case ConsoleKey.Oem3:
        if (cki.Modifiers.ToString().Contains("Shift")) //Could added handlers for Alt and Control, but not putted in here to keep the code small and simple
            data += "Ñ";
        else
            data += "ñ";
        break;
}
Console.WriteLine(data);
Console.ReadKey(true);

Итак, теперь вопрос имеет более широкий фокус ... Какие другие функции завершают свое выполнение только одной нажатой клавишей и возвращают то, что было нажато (замена ReadKey ())?Я думаю, что нет таких заменителей, но подтвержденный ответ был бы полезен.

Ответы [ 2 ]

1 голос
/ 31 марта 2012

Проблема не в том, что Консоль не знает, как обращаться с Юникодом (она делает, и правильно, проверьте эту ветку ).Проблема заключается в том, что вы понимаете нажатие клавиш на клавиатуре, перевод кодов клавиш, перевод кодов клавиш в символы и то, как работает метод ReadKey ().

Прежде всего: если вы хотитечитать последовательные символы, вместо этого использовать Console.ReadLine(), он выполняет всю математику за вас, и лучше.

Давайте рассмотрим следующую программу:

Console.WriteLine("Press a key to start (Enter to stop).");

var key = Console.ReadKey();
var allKeys = "";

while(key.Key != ConsoleKey.Enter)
{
    Console.WriteLine(key.KeyChar);
    allKeys += key.KeyChar;
    key = Console.ReadKey();
}

Она читаетключ от ввода, чем он добавляет его к строке.Не о чем беспокоиться, верно?Неправильно!На международной клавиатуре США вы можете сделать следующее:

  • Тип `+ a становится à
  • Тип Alt + 123 становится {
  • Тип Alt +3355 становится ←
  • Тип;как будто на испанской клавиатуре становится -

В зависимости от вашей клавиатуры, вы нажимаете другую клавишу для определенного символа.Иногда вы будете нажимать комбинацию клавиш.Первая комбинация, указанная выше, записывается как \0a в виде строки и кода ключа 0 (не в перечислении), а затем ConsoleKey.A.Итоговая строка теперь равна "\0á{←ñ".

. Alt + 123/3355 записывается как код клавиши 18 (это клавиша Alt).Преобразование числовых клавиш в символ выполняется ОС до его отправки на консоль.

Ввод ; на клавиатуре США или ñ на испанской клавиатуре покажет ConsoleKey.Oem1 (США) и ConsoleKey.Oem3 (испанский).

Хотя я не могу имитировать ваше поведение, возможно, это из-за того, что у меня нет вашего экрана, но очень похоже, что шрифт, который вы используете в качестве шрифта консоли, не поддерживает символы, отличные от Юникода.В Windows 7, по умолчанию, я не знаю, для других версий Windows.Также возможно, что кодовая страница вашей консоли установлена ​​неправильно.

Для суммирования
То, что составляет символ, зависит от раскладки клавиатуры, выбранной клавиатуры в международных настройках, выбранного языка,выбранная кодовая страница в консоли и разрешены ли комбинации клавиш (это ухудшается с IME!).Переход от KeyChar к обычному символу часто тривиален, но зависит от того, синхронизированы ли ваши системные настройки друг с другом.

Когда я запускаю ваши примеры в своей системе, у меня не такое поведение.Но опять же, у меня нет вашей системы.

Переход от ключа к персонажу - дело сложное.Я предлагаю вам не полагаться на свою способность заново изобретать то, что уже есть в системе.Это хорошая практика, чтобы попытаться увидеть, что происходит, но на самом деле вернуться к ReadLine;).

РЕДАКТИРОВАТЬ:
Я только что видел ваше последнее изменение.Обратите внимание, что у вас могут быть разные кодировки для ввода и вывода (Console.InputEncoding и Console.OutputEncoding).Я также хотел бы процитировать другой поток, чтобы подчеркнуть, что при переключении на Unicode кодовая страница больше не имеет значения.Это поведение по умолчанию в последних версиях Windows:

Если вы выберете шрифт Unicode, такой как Lucida Console или Consolas, вы сможете видеть и вводить символы Unicode на консоли независимо от того,что говорит ЧКП:

0 голосов
/ 19 апреля 2012

ReadLine () перенастраивает кодовую страницу для правильного использования расширенных символов ASCII и Unicode. ReadKey () оставляет его по умолчанию EN-US (кодовая страница 850).

Просто используйте кодовую страницу, которая печатает нужные вам символы, и все. См. http://en.wikipedia.org/wiki/Code_page для некоторых из них:)

Итак, для нажатия клавиши Ñ, решение будет таким:

Console.OutputEncoding = Encoding.GetEncoding(1252); //Also 28591 is valid for `Ñ` key, and others too
string data = string.Empty;
ConsoleKeyInfo cki;
cki = Console.ReadKey(true);
data += cki.KeyChar;
Console.WriteLine(data);
Console.ReadKey(true);

Простой:)

И примечание: в некоторых случаях также необходимо перенастроить свойство Console.InputEncoding!

Также обратите внимание, что если вы выберете другой шрифт для консоли (Lucida Console / Consolas), эта проблема по-прежнему будет происходить. Лотта благодарит пользователя Абеля за это, он назначил изменение шрифта для решения и заставил себя обнаружить, что это false.

...