Delphi

Delphi код символа – Получение ASCII-кода символа

Иллюстрированный самоучитель по Delphi 7 для начинающих › Приложение 2. Кодировка символов в Windows. [страница – 356] | Самоучители по программированию

Приложение 2. Кодировка символов в Windows.

В Windows в основном используется кодировка, которая называется ANSI. Разновидность набора ANSI, содержащая символы русского алфавита, называется Windows-1251.

В табл. П2.1 приведены коды некоторых служебных символов.

В табл. П2.2 и П2.3 приведены коды с символами 32-127 и 192-255.

Таблица П2.1. Некоторые служебные символы.

Код символаСимвол
9Табуляция
11Новая строка
13Конец абзаца
32Пробел

Таблица П2.2.. Символы с кодами 32-127.

СимволКодСимволКодСимволКодСимволКод
32Пробел42*52462>
33!43+535637
34к44,54664@
35#4555765А
36$46,56866В
37%47/57967С
38&48058:68D
3949159;69Е
40(50260<70F
41)51361=71G
 
72Н87W101е114r
73I88X102f115s
74J89Y103g116t
75К90Z104h117u
76L91[105i118v
77М92\105i119w
78N93]106j120x
79О94^107k121у
80Р95_108I122z
81Q96109m123[
82R97а110n124|
83S98b111o125]
84Т99с112p126~
85U100d113q127 
86V      

Таблица П2.3. Символы с кодами 192-255.

СимволКодСимволКодСимволКодСимволКод
192А201Й210Т219Ы
193Б202К211У220Ь
194В203Л212Ф221Э
195Г204М213X222Ю
196Д205Н214Ц223Я
197Е206О215Ч224а
198Ж207П216Ш225б
199З208Р217Щ226в
200И209С218Ъ227г
 
228д235л242т249щ
229е236м243у250ъ
230ж237н244ф251ы
231з238о245х252ь
232и239п246ц253э
233й240р247ч254ю
234к241с248ш255я

samoychiteli.ru

Символы в Delphi » DelphiComponent.ru

Для хранения и обработки символов используются переменные типа AnsiChar и wideChar. Тип AnsiChar представляет собой набор ANSI-символов, в котором каждый символ кодируется восьмиразрядным двоичным числом (байтом). Тип WideChar представляет собой набор символов в кодировке Unicode, в которой каждый символ кодируется двумя байтами. Для обеспечения совместимости с предыдущими версиями поддерживаетсятип Char, эквивалентный AnsiChar.

Значением переменной символьного типа может быть любой отображаемый символ:

  • буква русского или латинского алфавитов;
  • цифра;
  • знак препинания;
  • специальный символ, например, “новая строка”.

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

 

 

где:

  •  имя — имя переменной символьного типа;
  •  char — ключевое слово обозначения символьного типа.

 

Примеры:

 

 

Как и любая переменная программы, переменная типа char может получить значение в результате выполнения инструкции присваивания. Если переменная типа char получает значение в результате выполнения операции присваивания, то справа от знака := должно стоять выражение типа char, например, переменная типа char или символьная константа — символ, заключенный в кавычки.

В результате выполнения инструкций

переменная cl получает значение присваиванием значения константы, а переменная с2 — присваиванием значения переменной cl (предполагается, что переменные cl и с2 являются переменными символьного типа).

 

Переменную типа char можно сравнить с другой переменной типа char или с символьной константой. Сравнение основано на том, что каждому символу поставлено в соответствие число (см. приложение 2), причем символу ‘о’ соответствует число меньшее, чем символу У, символу ‘А’ — меньшее, чем ‘в’, символу У — меньшее, чем а.

Таким образом, можно записать:

 

' 0 ' ' 1 ' < . . < ' 9 ' < . . < ' A'<' B ' < . . <'Z ' ' a ' ' b ' < . . < ' z '

 

Символам русского алфавита соответствуют числа большие, чем символам латинского алфавита, при этом справедливо следующее:

  

' А ' ' В ' ' В ' < . . < ' Ю ' ' Я ' ' а ' ' б ' ' в ' < . . . < ' э ' ' ю ' <'я'

 

В тексте программы вместо символа можно указать его код, поставив перед числом оператор #. Например, вместо константы ‘Б’ можно записать #193. Такой способ записи, как правило, используют для записи служебных символов или символов, которые во время набора программы нельзя ввести с клавиатуры. К примеру, часто используемый при записи сообщений символ “новая строка” записывается так:   #13.

 

В программах обработки символьной информации часто используют функции chr и ord. Значением функции chr яеляется символ, код которого указан в качестве параметра. Например, в результате выполнения инструкции c:=Chr(32) переменной с будет присвоено значение пробел. Функция Ord позволяет определить код символа, который передается ей в качестве параметра. Например, в результате выполнения инструкции ki-ordf1*1 ) переменная k будет содержать число 42 — код символа *.

dle

Помоги проекту! Расскажи друзьям об этом сайте:

delphicomponent.ru

Delphi 2010. Работа с клавиатурой в условиях Unicode. — Delphi в Internet

Как я уже отмечал, начиная с Delphi 2009 введена полная поддержка Unicode.  Это замечательно, необходимо и важно. Однако, как ни крути, но не все толком понимают как работать-то? Я сейчас не имею ввиду профессиональных программистов, работающих постоянно с Delphi. Речь идёт о простых любителях, начинающих программистах, которые большую часть информации получают из Сети, в результате чего возникают всякие непредвиденные ситуации. Вот, например, ситуация — надо написать программу, которая будет отлавливать нажатия клавиш клавиатуры и записывать их в лог.  В Интернет есть масса примеров как организовать глобальный хук на клаву и считывать в лог виртуальные и скан-коды клавиш (подобная статья есть и у нас в блоге). Естественно, начинающий программист просто качает готовый пример и пробует транслировать эти самые коды в буковки…а они просто так не транслируются — получаем либо «кракозябры» либо нормальные буквы но не те.  И сидит такой начинающий программист, чешет затылок и другие части тела, не понимая что он делает не так? В лучшем случае лезет в опять в Сеть и с огромной вероятностью натыкается на подобного рода «рецепты-объяснения»:

В событиях OnKeyDown и OnKeyUp, Key является беззнаковым двухбайтовым (Word) значением, которое представляет виртуальную клавишу Windows. Для получания значения символа можно воспользоваться функцией Chr. В событии OnKeyPress параметр Key является значением Char, которое представляет символ ASCII.

Вроде все правильно. НО не для Delphi 2009-2010, при работе с русскими символами, так как во-первых, введена поддержка Unicode, а во-вторых ASCII никогда с роду не содержала русских букв (см.историю разработки кодировок).  И никогда, ни при каких обстоятельствах Вы не сможете перевести просто так виртуальную клавишу в русский символ функцией Chr.

Если не верите — проделайте такой простой эксперимент: откройте Delphi 2009-2010, создайте новое приложение и в событии onKeyUp для главной формы напишите такой код:

Теперь запустите приложение, переключитесь на русский язык и нажмите любую клавишу.

Вот результат нажатия русской буквы «Ы»:

Спрашивается: Чё за фигня? Где моя буковка «Ы»? И, что самое интересное, я ведь нажимал букву без Shift и CapsLock, а мне чего-то буква в верхнем регистре упала? Давайте разбираться в определениях. Так как без четкого знания определений мы с Вами в этих лабиринтах и хитросплетениях не разберемся никогда.

1. Скан-коды, виртуальные код и коды символов

Итак, с клавиатурой связано как минимум три разновидности кодов: скан-код, символьный код и виртуальный код. И далеко не все начинающие программисты понимают различия между ними.
Самая большая путаница со скан-кодами. Для начала, их существует две разновидности. Есть скан-коды «настоящие» — это то, что получает система прямо от клавиатуры, а есть скан-коды которые выдаются после того, как они будут обработаны в BIOS, которая интерпретирует, например, одновременное нажатие клавиш-модификаторов, а также справляется с текущей таблицей кодов символов и отправляет эти скан-коды в буфер клавиатуры.
Теперь посмотрим, как выглядит скан-код в принципе. На рисунке представлена оригинальная 84-кнопочная клавиатура IBM PC. Вот во времена существования этой клавиатуры и назначались скан-коды клавишам. Причем присваивались они слева-направо, начиная с клавиши Esc. Так клавиша Esc получила скан-код 1, а клавиша 1 — код 2 и т.д. Пока не будем кидаться в дебри дополнительных клавиш, которые появились на современных клавиатурах (там есть свои особенности присвоения скан-кодов), а уясним для себя следующее:

Скан-код — это идентификатор клавиши на клавиатуре и он один в чистом виде никак не может сам по себе описать символ в условиях unicode

Теперь двигаемся дальше. Разберемся с виртуальными кодами.

Виртуальные коды — это то, что использует система (Windows) для идентификации клавиш.

То есть, проведя простую аналогию, можно с большим допущением сказать, что виртуальный код клавиши — это тот же скан-код, но только не для BIOS, а для операционной системы, установленной на компьютере пользователя.

С некоторыми из констант, определяющих виртуальный код клавиш Вы можете ознакомиться в модуле windows.pas Delphi. Но, там отсутствуют коды для буквенно-цифровых клавиш, т.к. они совпадают с соответствующими символами из таблицы ASCII.

Теперь, я думаю, становится более-менее ясно почему при нажатии клавиши с буквой «ы» мы в примере получили заглавную букву «S»? Delphi в этом случае сработала идеально правильно  — выдала именно виртуальный код клавиши, как и полагается.

А для того, чтобы получить русскую букву нам необходимо знать третий код — код символа в таблице символов Unicode или, как мы посмотрим ниже, скан-код, виртуальный код и ещё один параметр — состояние клавиатуры.

Для того, чтобы продемонстрировать правильность работы Delphi, немного допишем наш пример.

Создайте такую глобальную переменную:

Теперь в обработчике события onKeyPress главной формы напишите такой код:

То есть, таким простым способом мы получим в переменную Ch уже не виртуальный, а код символа из таблицы Unicode, т.к. в переменную Key обработчика onKeyPress поступает уже не код, а символ.

В обработчике onKeyUp добавьте новую строку:

Запустите приложение и проверьте любую русскую букву. Второй ShowMessage вернет как и полагается верный символ в верной раскладке.

Чтобы убедиться, что в переменную Ch попадает именно Unicode, а не код из какой-то другой таблицы кодировок (например ANSI)  Вам достаточно вспомнить как располагаются символы в этой кодировке (см. историю кодировок) и посмотреть у переменной Ch первое слово. В Delphi это можно сделать, например вот так:

ShowMessage('Код символа = '+IntToStr(Ch)+#10#13+
'HEX представление = '+IntToHex(Ch,4)+#10#13+
'Символ = '+Chr(Ch));

В результате, для полюбившейся мне буквы «ы» получим:

Как видите, нет никаких ошибок в работе Delphi, функции ord и chr как работали со времен бородатого Pascal так и продолжают работать и выполнять свое назначение. Появилась только небольшая проблемка — как зная скан-код и виртуальный код клавиши получить код символа и, естественно сам символ из таблицы Unicode?

Самый простой вариант — это составить таблицу соответствия русских символов (строчных или прописных) из Unicode с виртуальными кодами клавиш. Для того, чтобы просто транслировать виртуальный код в букву этого будет вполне достаточно, а вот для полноценной работы — врядли. Необходимо также учитывать одновременное нажатие клавиш-модификаторов и прочие хитросплетения, чтобы верно транслировать большие и маленькие буквы, цифры, точки, запятые и т.д. Но, мы ведь не ищем лёгких путей? И в итоге доберемся до истины без всяких таблиц.

Теперь, немного разобравшись в определениях, посмотрим как, где и в каких условиях мы можем использовать коды клавиш.

2. Работа клавиатурой в Delphi 2010

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

А рассмотрим те возможности, которые предоставляют нам Delphi и Windows для работы с клавиатурой в принципе.

Итак, в начале рассмотрим как можно получить в свое распоряжение и виртуальный код клавиши и скан-код клавиши.  Чтобы получить в распоряжение эти коды воспользуемся функцией MapVirtualKey.

MapVirtualKey переводит виртуальный код клавиши в скан-код или символьное значение, или переводит скан-кода в код виртуальной клавиши.

Синтаксис функции в Delphi:

function MapVirtualKey(uCode, uMapType: cardial): cardinal

uCode — определяет виртуальный код клавиши или скан-кода. Как интерпретируется эта величина зависит от значения параметра uMapType

uMapType — Указывает на то как будет произведен перевод. Значение этого параметра зависит от значения параметра uCode и может принимать следующие значения:

MAPVK_VK_TO_VSC — uCode представляет собой виртуальный код клавиши и переводится в скан-код.  Если это виртуальный код клавиши  (что не делает различия между левыми и правыми клавишами-модификаторами ), то функция вернет значение скан-кода для левой клавиши-модификатора или буквенно-цифровой клавиши. Если перевода невозможен, то функция возвращает 0.

MAPVK_VSC_TO_VK uCode — это скан-код и переводится в виртуальный код клавиши.

MAPVK_VK_TO_CHAR — uCode виртуальный код клавиши и переводится в значение код символа из ASCII без смещение.

MAPVK_VSC_TO_VK_EX — для Windows NT/2000/XP: uCode это скан-код и переводится в виртуальный код клавиши, При этом различаются левые и правые модификаторы.

MAPVK_VK_TO_VSC_EX — то же самое, что и MAPVK_VK_TO_VSC, но с различием левых и правых модификаторов.

Теперь, воспользуемся этой функцией и попробуем получить значения скан-кодов и виртуальных кодов. Создаем или немного модифицируем наше тестовое приложение. У меня, например, для проверки работы с клавиатурой получилось вот такое приложение:

Для удобства работы можно использовать новый компонент Delphi 2010 с вкладки Touch палитры компонентов.

В Memo будем выводить всю, интересующую нас информацию.

Теперь в обработчике события onKeyUp главной форму пишем:

procedure TForm2.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
var VK, SC, C: cardinal;
begin
if b then  //слежение за клавиатурой включено
  begin
    SC := MapVirtualKey(Key, MAPVK_VK_TO_VSC);// получаем скан-код
    VK := MapVirtualKey(SC, MAPVK_VSC_TO_VK);// скан-код переводится в виртуальный код
    C := MapVirtualKey(VK, MAPVK_VK_TO_CHAR);// виртуальный код в код симола по ASCII
    //выводим всё, что только можно по нажатой кнопке
    Memo1.Lines.Add('++++ KeyUp() ++++');
    Memo1.Lines.Add('Вернула значение            ' + IntToStr(Key));
    Memo1.Lines.Add('++++ Значения функции MapVirtualKey() ++++');
    Memo1.Lines.Add('Скан-код клавиши            ' + IntToStr(SC));
    Memo1.Lines.Add('Виртуальный код клаиши      ' + IntToStr(VK));
    Memo1.Lines.Add('Не сдвинутое значение ASCII ' + IntToStr(C));
    Label5.Caption := IntToStr(Key);
    Label7.Caption := Chr(Key);
  end;
end;

А в обработчике события onKeyPress такой код:

procedure TForm2.FormKeyPress(Sender: TObject; var Key: Char);
begin
if b then
  begin
    Ch := Ord(Key);
    Memo1.Lines.Add('++++ Функция ORD() ++++');
    Memo1.Lines.Add('Вернула значение            ' + IntToStr(Ord(Key)));
  end;
end;

Запускаем приложение и проверяем работу функции MapVirtualKey:

Как и полагается для английской буквы виртуальный код совпадает с несдвинутым значением кода символа по ASCII и это же значение было возвращено нам в переменной Key процедуры обработки события onKeyUp. При этом обратите внимание на то, какое значение вернула функция ord() — она вернула верный код символа из ASCII или, что-то же самое, из начала таблицы Unicode.

Теперь переключаемся на русскую раскладку и проверяем ту же самую кнопку:

как и в первом случае — все значения кодов те же самые за исключением значения из функции ord() она как и полагается вернула значение кода символа с первым байтом равным 4.

Теперь пройдем немного дальше в наших изысканиях и посмотрим можно ли при работе с клавиатурой как-то учитывать текущую раскладку.

Смотрим, что нам говорит справка Delphi про функцию MapVirtualKeyEx:

MapVirtualKeyEx функция переводит виртуальный код клавиши в скан-код или символьное значение, или переводит скан-код в код виртуальной клавиши. Функция переводит код, используя язык ввода.

Синтаксис:

function MapVirtualKey(uCode, uMapType, dwhkl: cardial): cardinal

Первые два параметра те же, что и у предыдущей функции. А третий параметр:

dwhkl — Язык ввода, используется для перевода указанного кода. Этот параметр может быть любым идентификатором Язык ввода предварительно возвращенный функцией LoadKeyboardLayout.

Разберемся как получить dwhkl. Здесь есть два варианта: загрузить необходимый язык функцией LoadKeyboardLayout либо получить текущий язык с помощью функции GetKeyBoardLayout.  Не будем повторяться и дважды рассматривать возможности получения кодов клавиш, а лучше разберемся с идентификаторами языка ввода.

Первая функция получает значение текущего языка ввода для процесса:

GetKeyBoardLayout(dwLayout: cardinal)

dwLayout — идентификатор процесса для которого необходимо получить значение языка ввода. Если параметр равен нулю, то возвращается значение для текущего процесса.

Проверим работу функции. Пусть при включении режима слежения за клавиатурой (в моей программе за это отвечает кнопка и переменная b: boolean) выводится значение функции GetKeyboardLayout.

procedure TForm2.Button1Click(Sender: TObject);
begin
b := not b;
if b then
  begin
    Label2.Caption := 'Слежение';
    Label9.Caption:=IntToStr(GetKeyboardLayout(0));
  end
else
  Label2.Caption := 'Простой'
end;

Результат работы программы можно увидеть на рисунке:

Впервые столкнувшись с работой этой функции у меня возник резонный вопрос «Что мне с этим числом делать?» Ответ нашелся спустя несколько минут. Дело в том, что это число можно представить в несколько иной форме. Запишем вывод идентификатора в немного ином виде — возьмем только младшее слово:

Label9.Caption:=IntToStr(LoWord(GetKeyboardLayout(0)));

Теперь запустите снова программу и посмотрите на результат. Уже более знакомая картинка: русский язык имеет идентификатор 1049, а английский 1033.В HEX-форме эти же значения будут выглядеть как 0419 и 0409 соответственно.

Двигаемся дальше. Вторая функция — LoadKeyboardLayout загружает новый идентификатор языка.

Синтаксис:

LoadKeyboardLayout(pwszKLID: PWideChar; Flags: cardinal);

pwszKLID — указатель на буфер, который определяет имя идентификатора локали для загрузки. Это имя представляет собой строку, состоящую из шестнадцатеричного значения идентификатора языка (младшее слово) и идентификатора устройства (старшее  слово).

Flags может принимать одно из следующих значений:

KLF_ACTIVATE — если указанный идентификатор локали ввода еще не загружен, функция загружает и активирует его для текущего потока.

KLF_NOTELLSHELL предотвращает процедуру ShellProc. Это значение обычно используется, когда приложение загружает несколько идентификаторов языков ввода один за другим.

KLF_REORDER — перемещает указанный идентификатор локали в список идентификаторов локали ввода, делая этот идентификатор активным для текущего потока.Также могут использоваться флаги  KLF_REPLACELANG, KLF_SUBSTITUTE_OK KLF_SETFORPROCESS.

Попробуем применить все вышеизложенное на практике. Пусть по какому-либо событию в нашем приложении меняется идентификатор языка ввода. Я для этого выбрал клик по кнопке:

procedure TForm2.Button2Click(Sender: TObject);
var newHKL: PWideChar;
begin
  hkl:=LoWord(GetKeyboardLayout(0)); //смотрим текущую локаль
  if hkl=1049 then //текущия язык - русский
    begin
      hkl:=1033; //изменяем на английскую
      newHKL:=PChar('0000'+IntToHex(hkl,4));
      LoadKeyboardLayout(newHKL,KLF_ACTIVATE);
      Button2.Caption:='En';
    end
  else
    begin   //текущий язык - английский
      hkl:=1049;
      newHKL:=PChar('0000'+IntToHex(1049,4));
      LoadKeyboardLayout(newHKL,KLF_ACTIVATE);
      Button2.Caption:='Ru';
    end;
  Label9.Caption:=IntToStr(hkl);
  label11.Caption:=IntToHex(hkl,4);
end;

В результате при клике по кнопке текущая раскладка (или в терминах Win XP — язык) меняется на противоположную, т.е. русская раскладка меняется на английскую и наоборот.

Теперь можно, не останавливая слежение за нажатыми кнопками клавиатуры, спокойно менять раскладку на противоположную одним кликом по кнопке.

Двигаемся дальше.  Про получение виртуального и скан-кода разобрались, как получить или сменить идентификатор языка ввода узнали, осталось научиться применять полученные знания для определения русских символов в используемой таблице Unicode.

Как я уже отмечал выше, функция Chr для перевода виртуального кода в русский символ не подходит. Поэтому будем пользоваться тем, что предлагает в наше распоряжение Windows API. А предлагается нам на выбор две функции:

  1. ToAscii
  2. ToUnicode

Есть та же ToAsciiEx и ToUnicodeEx, которые используют в качестве дополнительного параметра текущие локали, но мы их рассматривать не будем, будем так сказать зреть в корень.

Так как нам необходимо научиться определять по скан-коду и виртуальному коду русские символы, то первая функция ToAscii сразу отметается в сторону, остается ToUnicode.

Синтаксис функции в Delphi следующий:

ToUnicode(wVirtKey, wScanCode: cardinal;lpKeyState: TKeyBoardState; pwszBuff: void type; cchBuff: integer; wFlags: Cardinal):integer;

wVirtKey и wScanCode — виртуальный и скан-код клавиши, которая должна быть оттранслирована в символ

lpKeyState — переменная, определяющая состояние клавиатуры в момент трансляции. Представляет собой массив на 256 элементов типа byte.

pwszBuff — указатель на буфер в котором будет хранится символ

cchBuff — размер буфера

wFlags — флаги. Допускается использовать 0.

Функция возвращает:

в переменную pwszBuff символ.

в result:

-1, если трансляция не удалась. Это может произойти, если вы, например, хотели оттранслировать коды

webdelphi.ru

Отправить ответ

avatar
  Подписаться  
Уведомление о