Аппаратное обеспечение персонального компьютера© Александр Фролов, Григорий ФроловТом 33, М.: Диалог-МИФИ, 1997, 304 стр. |
В этом разделе мы подробно рассмотрим одно из важнейших устройств персонального компьютера - клавиатуру. Практически ни одна программа не обходится без обращения к клавиатуре.
Программа может использовать клавиатуру по-разному. Она может задерживать свое выполнение до тех пор, пока пользователь не введет какое-нибудь число или пока не нажмет какую-нибудь клавишу. Выполняя некоторую работу, программа может периодически проверять, была ли нажата клавиша, изменяющая режим работы программы. Резидентные программы могут активизироваться, когда пользователь нажимает заранее определенную комбинацию. Можно использовать прерывание, вырабатываемое клавиатурой, например, для завершения работы программы.
Мы расскажем о работе с клавиатурой в среде MS-DOS на разных уровнях - от использования клавиатурных портов ввода/вывода до средств, предоставляемых стандартными библиотеками трансляторов C. Какой уровень вам следует выбрать, зависит от решаемой задачи. Единственное, что можно порекомендовать - это использовать по возможности средства высокого уровня. Если ваша программа обращается к клавиатуре через порты ввода/вывода, ее работоспособность может оказаться зависимой от типа клавиатуры и от модели компьютера.
Что же касается методики работы с клавиатурой в операционных системах Microsoft Windows, то она была описана в 11 томе «Библиотеки системного программиста», который называется «Операционная система Microsoft Windows для программиста».
Клавиатура выполнена, как правило, в виде отдельного устройства, подключаемого к компьютеру тонким кабелем. Малогабаритные блокнотные компьютеры содержат встроенную клавиатуру.
Что же находится внутри клавиатуры?
Оказывается, там есть компьютер! Только этот компьютер состоит из одной микросхемы и выполняет специализированные функции. Когда вы нажимаете на клавиши, он посылает номер нажатой клавиши в центральный компьютер.
Если рассмотреть сильно упрощенную принципиальную схему клавиатуры, представленную на рисунке, можно заметить, что все клавиши находятся в узлах матрицы (рис. 2.1).
Рис.2.1. Упрощенная схема клавиатуры
Все горизонтальные линии матрицы подключены через резисторы к источнику питания +5 В. Клавиатурный компьютер имеет два порта - выходной и входной. Входной порт подключен к горизонтальным линиям матрицы (X0-X4), а выходной - к вертикальным (Y0-Y5).
Устанавливая по очереди на каждой из вертикальных линий уровень напряжения, соответствующий логическому нулю, клавиатурный компьютер опрашивает состояние горизонтальных линий. Если ни одна клавиша не нажата, уровень напряжения на всех горизонтальных линиях соответствует логической единице (так как все эти линии подключены к источнику питания +5 В через резисторы).
Если вы нажмете на какую-либо клавишу, то соответствующая вертикальная и горизонтальная линии окажутся замкнутыми. Когда на этой вертикальной линии процессор установит значение логического нуля, то уровень напряжения на горизонтальной линии также будет соответствовать логическому нулю.
Как только на одной из горизонтальных линий появится уровень логического нуля, клавиатурный процессор фиксирует нажатие на клавишу. Он посылает в центральный компьютер запрос на прерывание и номер клавиши в матрице. Аналогичные действия выполняются и тогда, когда вы отпускаете нажатую ранее клавишу.
Номер клавиши, посылаемый клавиатурным процессором, однозначно зависит от схемы клавиатурной матрицы, но не от обозначений, нанесенных на поверхность клавиш. Этот номер называется скан-кодом (Scan Code). Слово scan ("сканирование"), подчеркивает тот факт, что клавиатурный компьютер сканирует клавиатуру для поиска нажатой клавиши.
Обычно программе нужен не порядковый номер нажатой клавиши, а код, соответствующий обозначению на этой клавише (код ASCII).
Код ASCII не связан напрямую со скан-кодом, так как одной и той же клавише могут соответствовать несколько значений кода ASCII в зависимости от состояния других клавиш. Например, клавиша с обозначением «1» используется еще и для ввода символа «!» (если она была нажата вместе с клавишей <Shift>).
Поэтому все преобразования скан-кода в код ASCII выполняются программно. Как правило, в операционной системе MS-DOS эти преобразования выполняют модули BIOS. Для использования символов кириллицы эти модули расширяются клавиатурными драйверами, как входящими в состав локализованных версий MS-DOS, так и созданными в виде отдельных программ.
Если нажать на клавишу и не отпускать ее, клавиатура перейдет в режим автоповтора. При этом в компьютер автоматически через некоторый период времени, называемый периодом автоповтора, посылается код нажатой клавиши. Режим автоповтора облегчает ввод с клавиатуры большого количества одинаковых символов.
Следует отметить, что клавиатура содержит внутренний 16-байтовый буфер, через который она осуществляет обмен данными с компьютером.
До недавнего времени существовали три различных типа клавиатуры. Это клавиатура для компьютеров IBM PC/XT, 84-клавишная клавиатура для IBM PC/AT и 101-клавишная (расширенная) клавиатура для IBM PC/AT. Некоторые клавиатуры имеют переключатель режима работы (XT/AT), расположенный на нижней крышке. Он должен быть установлен в правильное положение.
После того как операционная система Microsoft Windows получила широкое распространение, специально для нее был создан новый тип клавиатуры. К обычной клавиатуре типа IBM PC/AT были добавлены две кнопки, первая из которых дублирует вызов меню Start, выполняемый при помощи левой клавиши мыши, а вторая – вызов того же меню при помощи правой клавиши мыши.
Назначение портов, предназначенных для работы с клавиатурой, зависят от типа компьютера.
Для работы с клавиатурой типа IBM PC/XT используются порты с адресами 60h и 61h.
Порт 60h доступен только для чтения. После выполнения этой операции он содержит скан-код последней нажатой клавиши.
Порт 61h доступен как для чтения, так и для записи. Он управляет не только клавиатурой, но и другими устройствами компьютера, например, работой встроенного динамика. Если в старший бит порта 61h записать значение 1, клавиатура будет заблокирована, если 0 - разблокирована.
Так как порт 61h управляет не только клавиатурой, при изменении содержимого старшего бита необходимо сохранить состояние остальных битов этого порта. Для этого можно сначала выполнить чтение содержимого порта в регистр, изменить состояние старшего бита, затем выполнить запись нового значения в порт:
. . . in al, 61h or al, 80h out 61h, al . . .
Современные компьютеры позволяют управлять скоростными характеристиками клавиатуры, а также зажигать или гасить светодиоды Scroll Lock, Num Lock и Caps Lock, расположенные на лицевой панели клавиатуры.
Для расширенного управления клавиатурой применяется порт 60h в режиме записи. Этот порт служит для управления подчиненным процессором Intel 8042, ответственным за обмен данными с клавиатурным компьютером, или его аналогом, установленным на системной плате компьютера.
При использовании порта 60h на запись программа дополнительно получает следующие возможности:
· установка времени ожидания перед переходом клавиатуры в режим автоповтора;
· установка периода генерации скан-кода в режиме автоповтора;
· управление светодиодами, расположенными на лицевой панели клавиатуры.
Процессор 8042 обслуживает не только клавиатуру, но и другие системы компьютера. Через порт 64h, например, выполняется сброс (отключение) процессора 80286 для возврата из защищенного режима работы в реальный. Подробности об этом вы можете узнать из 6 тома «Библиотеки системного программиста», который называется «Защищенный режим процессоров Intel 80286/80386/80486».
Перед тем как посылать команду процессору 8042, необходимо убедиться в том, что его внутренняя очередь команд пуста. Это можно сделать, прочитав слово состояния 8042 из порта с адресом 64h. Бит с номером 1 должен быть равен нулю.
Приведем фрагмент программы, составленной на языке ассемблера, проверяющий состояние очереди команд процессора 8042:
. . . ; Счетчик для ограничения времени ожидания готовности 8042 mov cx,0 wait_loop: ; Читаем порт состояния процессора 8042 in al, 64h and al, 00000010b ; флаг готовности ; Ожидаем готовность процессора 8042 к приему команды loopnz wait_loop . . .
После того, как программа дождется готовности процессора 8042, она может послать ему команду, записав ее в порт с адресом 60h:
mov al, cmd ; команда для 8042 out 60h, al ; вывод команды в 8042
Некоторые команды состоят более чем из одного байта. Второй и следующие байты таких команд необходимо записывать в порт 60h, предварительно убедившись в готовности процессора 8042 с помощью приведенной выше последовательности команд. В большинстве случаев можно также использовать простую временную задержку:
mov al, cmd_byte1 out 60h, al mov cx, 2000h wait_loop: loop wait_loop mov al, cmd_byte2 out 60h, al
Мы приведем формат двух команд процессора 8042, имеющих отношение к работе с клавиатурой - команду установки задержки и периода автоповтора и команду управления светодиодами, расположенными на клавиатуре.
Для установки характеристик режима автоповтора в порт 60h необходимо записать код команды 0F3h, затем байт, определяющий характеристики режима. Ниже вы найдете описание полей байта режима автоповтора:
Биты |
Описание |
0-4 |
Период автоповтора, который определяет количество посылок скан-кода, генерируемых процессором клавиатуры в одну секунду. Можно использовать не только те значения, которые приведены ниже, но и промежуточные, например, 9 или 15h. 0 30.0 1 26.7 2 24.0 4 20.0 8 15.0 0Ah 10.0 0Dh 9.2 10h 7.5 14h 5.0 1Fh 2.0 |
5-6 |
Задержка включения режима автоповтора, mc: 00 250 01 500 10 750 11 1000 |
7 |
Зарезервировано и должно быть равно нулю |
Первоначально при инициализации системы BIOS устанавливает период задержки для включения режима автоповтора равным 500 мс при периоде автоповтора, равным 10 повторам в секунду. Если это слишком медленно для вас, вы можете установить другие значения.
Для управления светодиодами, расположенными на лицевой панели клавиатуры, используйте команду 0EDh. Вслед за этой командой в порт 60h необходимо записать байт, имеющий следующий формат:
Биты |
Описание |
0 |
1 – включить светодиод Scroll Lock; 0 – выключить светдиод Scroll Lock |
1 |
1 – включить светодиод Num Lock; 0 – выключить светодиод Num Lock |
2 |
1 – включить светодиод Caps Lock; 0 – включить светодиод Caps Lock |
Приведем пример простейшей программы KBDLED, управляющей светодиодами, расположенными на лицевой панели клавиатуры (листинг 2.1). Такое управление может выполняться только при использовании порта 60h, так как BIOS не содержит никаких подходящих для этого функций. Наша программа после запуска включит все светодиоды и будет ожидать, пока вы не нажмете любую клавишу. Затем программа выключит светодиоды.
Заметим, что программа KBDLED может не работать на виртуальной машине DOS, создаваемой, например, в операционной системе Microsoft Windows NT.
Листинг 2.1. Файл kbdled\kbdled.c
// ===================================================== // Переключение светодиодов на клавиатуре // // (C) Фролов А.В, 1997 // // E-mail: frolov@glas.apc.org // WWW: http://www.glasnet.ru/~frolov // или // http://www.dials.ccas.ru/frolov // ===================================================== #include <stdio.h> #include <conio.h> int main(void) { int i; printf("KBDLED, (c) A. Frolov, 1997\n"); // Посылаем процессору клавиатуры // команду управления светодиодами outp(0x60,0xed); // Перед посылкой второго байта команды // выполняем небольшую задержку for(i=0; i<4000; i++); // Выводим второй байт команды, младшие три бита // которого определяют состояние светодиодов // на лицевой панели клавиатуры outp(0x60,7); printf("Нажмите любую клавишу для выключения " "светодиодов\n"); // Задерживаем выполнение программы, пока // пользователь не нажмет на любую клавишу getch(); // Выключаем все светодиоды outp(0x60,0xed); for(i=0; i<4000; i++); outp(0x60,0); return 0; }
Клавиатура подключена к линии прерывания IRQ1. Этой линии соответствует прерывание INT 09h.
Клавиатурное прерывание обслуживается BIOS, однако драйверы клавиатуры и резидентные программы могут организовывать дополнительную обработку прерывания INT 09h. Для этого может быть использована цепочка обработчиков прерывания.
Как работает стандартный обработчик клавиатурного прерывания, входящий в состав BIOS?
Этот обработчик выполняет следующие действия:
· читает из порта 60h скан-код нажатой клавиши;
· записывает вычисленное по скан-коду значение кода ASCII нажатой клавиши в специальный буфер клавиатуры, расположенный в области данных BIOS;
· устанавливает в единицу бит 7 порта 61h, разрешая дальнейшую работу клавиатуры;
· возвращает этот бит в исходное состояние;
· записывает в порт 20h значение 20h для правильного завершения обработки аппаратного прерывания.
Обработчик прерывания INT 09h не просто записывает значение кода ASCII в буфер клавиатуры, но также выполняет и другие действия. Например, он дополнительно отслеживает нажатие пользователем таких комбинаций клавиш, как <Ctrl+Alt+Delete>, обрабатывает специальные клавиши <PrintScreen> и <SysReq>. При вычислении кода ASCII нажатой клавиши учитывается состояние клавиш <Shift> и <CapsLock>.
Буфер клавиатуры имеет длину 32 байта и расположен в компьютере IBM PC/XT по адресу 0000h:041Eh.
В компьютерах моделей IBM PC/AT и IBM PS/2 расположение клавиатурного буфера задается содержимым двух слов памяти с адресами 0000h:0480h (смещение адреса начала буфера) и 0000h:0482h (смещение конца буфера). Обычно эти ячейки памяти содержат значения, соответственно, 001Eh и 003Eh. Так как смещения заданы относительно сегментного адреса 0040h, то стандартное расположение клавиатурного буфера в IBM PC/AT и IBM PS/2 соответствует его расположению в IBM PC/XT.
Буфер клавиатуры организован циклически. Это означает, что при его переполнении самые старые значения будут потеряны. Две ячейки памяти, находящиеся в области данных BIOS с адресами 0000h:041Ah и 0000h:041Ch содержат, соответственно, указатели на начало и конец буфера. Если значения этих указателей равны друг другу, буфер пуст.
Заметим, что вы можете удалить все символы из буфера клавиатуры, установив оба указателя на начало буфера. Однако есть более предпочтительный способ с использованием прерывания BIOS INT 16h, функции которого мы опишем позже в этой главе.
Указателями на начало и конец клавиатурного буфера обычно управляют обработчики прерываний INT 09h и INT 16h. Программа извлекает из буфера коды нажатых клавиш, используя различные функции прерывания INT 16h.
При переполнении внутреннего буфера клавиатуры или буфера, расположенного в области данных BIOS программа-обработчик прерывания INT 09h генерирует звуковой сигнал.
В программах MS-DOS у вас едва ли появится необходимость непосредственного манипулирования содержимым буфера клавиатуры - вы можете использовать прерывание BIOS INT 16h для выполнения практически всех клавиатурных операций.
Помимо управления содержимым буфера клавиатуры, обработчик прерывания INT 09h отслеживает так называемые переключающие клавиши - <NumLock>, <ScrollLock>, <CapsLock>, <Insert>. Состояние этих клавиш записывается в область данных BIOS в два байта с адресами 0000h:0417h и 0000h:0418h.
Формат байта 0000h:0417h:
Биты |
Описание |
0 |
Нажата правая клавиша <Shift> |
1 |
Нажата левая клавиша <Shift> |
2 |
Нажата комбинация клавиш <Ctrl+Shift> с любой стороны |
3 |
Нажата комбинация клавиш <Alt+Shift> с любой стороны |
4 |
Состояние клавиши <ScrollLock> |
5 |
Состояние клавиши <NumLock> |
6 |
Состояние клавиши <CapsLock> |
7 |
Состояние клавиши <Insert> |
Формат байта 0000h:0418h:
Биты |
Описание |
0 |
Нажата левая клавиша <Shift> вместе с клавишей <Control> |
1 |
Нажата левая клавиша <Shift> вместе с клавишей <Alt> |
2 |
Нажата клавиша <SysReq> |
3 |
Состояние клавиши <Pause> |
4 |
Нажата клавиша <ScrollLock> |
5 |
Нажата клавиша <NumLock> |
6 |
Нажата клавиша <CapsLock> |
7 |
Нажата клавиша <Insert> |
Если вы изменяете состояние светодиодов на панели клавиатуры, не забывайте устанавливать соответствующие биты в байтах состояния клавиатуры.
Программой обработки прерывания INT 09h отслеживаются некоторые комбинации клавиш. Ниже приведены эти комбинации и действия, выполняемые обработчиком прерывания при их обнаружении:
Комбинация клавиш |
Выполняемые действия |
<Control+Alt+Delete> |
Сброс и перезагрузка системы |
<Control+NumLock>, <Pause> |
Перевод компьютера в состояние ожидания до тех пор, пока пользователь не нажмет любую клавишу |
<Shift+PrintScreen> |
Распечатка на принтере содержимого видеопамяти |
<Control+Break> |
Выполнение прерывания INT 1Bh, завершающего работу программы |
Многие типы клавиатур имеют отдельную альтернативную цифровую панель, напоминающую клавиатуру калькулятора. Если одновременно с нажатием на клавишу <Alt> набрать на этой панели число, не большее, чем 255 и не равное 0, то это число будет помещено в буфер клавиатуры, как будто бы оно было введено при помощи одной клавиши. Это число будет также записано в слово, расположенное в области данных BIOS по адресу 0000h:0419h.
Заметим, что упомянутый способ работает и в приложениях Microsoft Windows.
Набор функций для работы с клавиатурой, предоставляемый в распоряжение программиста прерыванием BIOS INT 16h, включает в себя функции для выборки кода нажатого символа из буфера с ожиданием нажатия, функции для проверки содержимого буфера и для управления содержимым буфера, функции для изменения скоростных характеристик клавиатуры.
Функция 00h выполняет чтение кода символа из буфера клавиатуры, если он там есть. Если буфер клавиатуры пуст, программа переводится в состояние ожидания до тех пор, пока не будет нажата какая-нибудь клавиша. Скан-код и код ASCII нажатой клавиши передаются программе.
Приведем формат вызова функции:
Регистры на входе: |
AH = 00h |
Регистры на выходе: |
AL = код ASCII символа или 0, если AH содержит расширенный код ASCII символа; AH = скан-код или расширенный код ASCII символа, если AL=0 |
Приведем таблицу скан-кодов:
01 |
Esc |
12 |
E |
23 |
H |
34 |
. > |
45 |
NumLock |
02 |
1 ! |
13 |
R |
24 |
J |
35 |
/ ? |
46 |
ScrLock |
03 |
2 @ |
14 |
T |
25 |
K |
36 |
Shift прав. |
47 |
Home [7] |
04 |
3 # |
15 |
Y |
26 |
L |
37 |
PrtSc |
48 |
Up [8] |
05 |
4 $ |
16 |
U |
27 |
; : |
38 |
Alt |
49 |
PgUp [9] |
06 |
5 % |
17 |
I |
28 |
‘ “ |
39 |
Пробел |
4A |
[-] |
07 |
6 ^ |
18 |
O |
29 |
` ~ |
3A |
CapsLock |
4B |
<- [4] |
08 |
7 & |
19 |
P |
2A |
Shift лев. |
3B |
F1 |
4C |
[5] |
09 |
8 * |
1A |
[ { |
2B |
\ | |
3C |
F2 |
4D |
-> [6] |
0A |
9 ( |
1B |
] } |
2C |
Z |
3D |
F3 |
4E |
[+] |
0B |
0 ) |
1C |
Enter |
2D |
X |
3E |
F4 |
4F |
End [1] |
0C |
- _ |
1D |
Ctrl |
2E |
C |
3F |
F5 |
50 |
Dn [2] |
0D |
= + |
1E |
A |
2F |
V |
40 |
F6 |
51 |
PgDn [3] |
0E |
Bksp |
1F |
S |
30 |
B |
41 |
F7 |
52 |
Ins [0] |
0F |
Tab |
20 |
D |
31 |
N |
42 |
F8 |
53 |
Del [.] |
10 |
Q |
21 |
F |
32 |
M |
43 |
F9 |
||
11 |
W |
22 |
G |
33 |
, < |
44 |
F10 |
Для остальных клавиш функция 00h прерывания INT 16h возвращает расширенный код ASCII:
F1 |
3b |
Shift+F1 |
54 |
Ctrl+F1 |
5e |
Alt+F1 |
68 |
F2 |
3c |
Shift+F2 |
55 |
Ctrl+F2 |
5f |
Alt+F2 |
69 |
F3 |
3d |
Shift+F3 |
56 |
Ctrl+F3 |
60 |
Alt+F3 |
6a |
F4 |
3e |
Shift+F4 |
57 |
Ctrl+F4 |
61 |
Alt+F4 |
6b |
F5 |
3f |
Shift+F5 |
58 |
Ctrl+F5 |
62 |
Alt+F5 |
6c |
F6 |
40 |
Shift+F6 |
59 |
Ctrl+F6 |
63 |
Alt+F6 |
6d |
F7 |
41 |
Shift+F7 |
5a |
Ctrl+F7 |
64 |
Alt+F7 |
6e |
F8 |
42 |
Shift+F8 |
5b |
Ctrl+F8 |
65 |
Alt+F8 |
6f |
F9 |
43 |
Shift+F9 |
5c |
Ctrl+F9 |
66 |
Alt+F9 |
70 |
F10 |
44 |
Shift+F10 |
5d |
Ctrl+F10 |
67 |
Alt+F10 |
71 |
Alt+A |
1E |
Alt+P |
19 |
Alt+3 |
7A |
Down |
50 |
Alt+B |
30 |
Alt+Q |
10 |
Alt+4 |
7B |
Left |
4B |
Alt+C |
2E |
Alt+R |
13 |
Alt+5 |
7C |
Right |
4D |
Alt+D |
20 |
Alt+S |
1F |
Alt+6 |
7D |
Up |
48 |
Alt+E |
12 |
Alt+T |
14 |
Alt+7 |
7E |
End |
4F |
Alt+S |
21 |
Alt+U |
16 |
Alt+8 |
7F |
Home |
47 |
Alt+G |
22 |
Alt+V |
2F |
Alt+9 |
80 |
PgDn |
51 |
Alt+H |
23 |
Alt+W |
11 |
Alt+- |
82 |
PdUp |
49 |
Alt+I |
17 |
Alt+X |
2D |
Alt+= |
83 |
||
Alt+J |
24 |
Alt+Y |
15 |
Ctrl+Left |
73 |
||
Alt+K |
25 |
Alt+Z |
2C |
Ctrl+Right |
74 |
||
Alt+L |
26 |
Shift+Tab |
0F |
Ctrl+End |
75 |
||
Alt+M |
32 |
Alt+0 |
81 |
Insert |
52 |
Ctrl+Home |
77 |
Alt+N |
31 |
Alt+1 |
78 |
Delete |
53 |
Ctrl+PgDn |
76 |
Alt+O |
18 |
Alt+2 |
79 |
PrintScr |
72 |
Ctrl+PgUp |
84 |
В следующей таблице приведены скан-коды клавиш, имеющихся только на 101-клавишной клавиатуре:
F11 |
85 |
Alt-Bksp |
0e |
Alt- Д / |
a4 |
F12 |
86 |
Alt-Enter |
1c |
Alt- Д * |
37 |
Shft-F11 |
87 |
Alt-Esc |
01 |
Alt- Д - |
4a |
Shft-F12 |
88 |
Alt-Tab |
a5 |
Alt- Д + |
4e |
Ctrl-F11 |
89 |
Ctrl-Tab |
94 |
Alt- Д Enter |
a6 |
Ctrl-F12 |
8a |
||||
Alt-F11 |
8b |
Alt-up Up |
98 |
Ctrl- Д / |
95 |
Alt-F12 |
8c |
Alt-down Dn |
a0 |
Ctrl- Д * |
96 |
Alt-[ |
1a |
Alt-left <- |
9b |
Ctrl- Д - |
8e |
Alt-] |
1b |
Alt-right -> |
9d |
Ctrl- Д + |
90 |
Alt-; |
27 |
||||
Alt-' |
28 |
Alt-Delete |
a3 |
Ctrl- Д Up [8] |
8d |
Alt-` |
29 |
Alt-End |
9f |
Ctrl- Д 5 [5] |
8f |
Alt-\ |
2b |
Alt-Home |
97 |
Ctrl- Д Dn [2] |
91 |
Alt-, |
33 |
Alt-Insert |
a2 |
Ctrl- Д Ins[0] |
92 |
Alt-. |
34 |
Alt-PageUp |
99 |
Ctrl- Д Del[.] |
93 |
Буква "Д" здесь обозначает дополнительную клавиатуру.
Для демонстрации использования функции 00h прерывания INT 16h мы подготовили программу, выводящую на экран скан-коды и коды ASCII нажимаемых клавиш (листинг 2.2).
Листинг 2.2. Файл kbdscan\kbdscan.c
// ===================================================== // Просмотр клавиатурных скан-кодов и кодов ASCII // // (C) Фролов А.В, 1997 // // E-mail: frolov@glas.apc.org // WWW: http://www.glasnet.ru/~frolov // или // http://www.dials.ccas.ru/frolov // ===================================================== #include <stdio.h> #include <dos.h> int main(void) { union REGS rg; printf("KBDSCAN, (c) A. Frolov, 1997\n" "Press <ESC> to exit\n"); for(;;) { // Вызываем прерывание INT 16h rg.h.ah = 0; int86(0x16, &rg, &rg); // Выводим на экран содержимое регистров AH и AL, // содержащих, соответственно, скан-код и код ASCII // нажатой клавиши printf("\nScan = %02.2X Ascii = %02.2X", rg.h.ah, rg.h.al); // Если была нажата клавиша ESC, завершаем работу // программы if(rg.h.ah == 1) break; } return 0; }
Функция 01h поможет вам проверить состояние буфера клавиатуры - есть там коды нажатых клавиш или нет. При этом программа не переводится в состояние ожидания, даже если буфер клавиатуры пуст. В этом случае в регистре флагов флаг ZF устанавливается в единицу и управление возвращается программе.
Формат вызова функции представлен ниже:
Регистры на входе: |
AH = 01h |
Регистры на выходе: |
ZF = 0, если в буфере имеется код нажатой клавиши; ZF = 1, если буфер клавиатуры пуст; AL = код ASCII символа или 0, если AH содержит расширенный код ASCII символа; AH = скан-код или расширенный код ASCII символа, если AL=0 |
Эту функцию удобно использовать во время выполнения какого-либо длительного процесса (например, форматирования диска или передачи данных по линии связи) для прерывания этого процесса по запросу пользователя.
Кроме того, функцию 01h можно применять вместе с функцией 00h для сброса содержимого клавиатурного буфера. Для этого в цикле повторяют вызов функции 01h, вслед за которым идет вызов функции 00h при условии, что буфер клавиатуры не пуст.
Сброс буфера клавиатуры полезно выполнять перед вводом ответственной информации, так как если пользователь случайно нажмет одну и ту же клавишу несколько раз, в буфере клавиатуры могут оказаться лишние символы.
Приведем исходный текст программы CHKBUF, выводящей на экран в цикле символ '*' (листинг 2.3). Если нажать любую клавишу, кроме <Esc>, программа выводит на экран строку текста - инструкцию для завершения работы программы. Если же нажать на клавишу <Esc>, работа программы будет завершена.
Листинг 2.3. Файл chkbuf\chkbuf.c
// ===================================================== // Демонстрация способа проверки буфера клавиатуры // // (C) Фролов А.В, 1997 // // E-mail: frolov@glas.apc.org // WWW: http://www.glasnet.ru/~frolov // или // http://www.dials.ccas.ru/frolov // ===================================================== #include <stdio.h> #include <dos.h> int main(void) { union REGS rg; int i, zflag; printf("CHKBUF, (c) A. Frolov, 1997\n"); for(;;) { // Выводим в цикле символ '*' putchar('*'); // Небольшая задержка во времени for(i=0; i<30000; i++); // Вызываем прерывание INT 16h для проверки буфера // клавиатуры. Устанавливаем флаг, который будет сброшен // при нажатии на любую клавишу zflag = 1; _asm { mov ax, 0100h int 16h // Если клавишу не нажимали, // продолжаем выполнение программы jz nokey // В противном случае сбрасываем флаг mov zflag, 0 nokey: } if(zflag == 0) { // Если флаг сброшен, читаем код нажатой клавиши из // буфера при помощи функции 01h прерывания INT 16h rg.h.ah = 0; int86(0x16, &rg, &rg); // Если была нажата клавиша <Esc>, // завершаем работу программы if(rg.h.ah == 1) { // Выводим на экран содержимое регистров AH и AL, // содержащих, соответственно, скан-код и код ASCII // нажатой клавиши printf("\nScan = %02.2X Ascii = %02.2X", rg.h.ah, rg.h.al); break; } else printf("\nPress <ESC> to exit\n"); } } return 0; }
Функция 02h возвращает в регистре AL состояние переключающих клавиш, таких как <Shift>, <Control>, <Alt>, <ScrollLock>, <NumLock>, <CapsLock>, <Insert>:
Регистры на входе: |
AH = 02h |
Регистры на выходе: |
AL = Байт состояния переключающих клавиш |
Формат байта состояния соответствует формату байта, находящегося в области данных BIOS по адресу 0000h:0417h:
Биты |
Описание |
0 |
Нажата правая клавиша <Shift> |
1 |
Нажата левая клавиша <Shift> |
2 |
Нажата комбинация клавиш <Control+Shift> с левой или правой стороны |
3 |
Нажата комбинация клавиш <Alt+Shift> с левой или правой стороны |
4 |
Состояние клавиши <ScrollLock> |
5 |
Состояние клавиши <NumLock> |
6 |
Состояние клавиши <CapsLock> |
7 |
Состояние клавиши <Insert> |
Функция 02h может быть использована для анализа текущего состояния переключающих клавиш.
Ниже показан фрагмент кода, в котором проверяется состояние клавиши <CapsLock>:
rg.h.ah = 2; int86(0x16, &rg, &rg); if((rg.h.al & 0x40) == 0) { // Клавиша <CapsLock> не нажата, // соответствующий светодиод не горит . . . } else { // Клавиша <CapsLock> нажата . . . }
Мы уже рассказывали о возможности изменения временных характеристик клавиатуры. Если BIOS, установленная в вашей машине, изготовлена после 15 декабря 1985 года, вы можете воспользоваться функцией 03h для ускорения (или замедления) работы клавиатуры:
Регистры на входе: |
AH = 03h; AL = 05h; BL = Период автоповтора (количество повторов за одну секунду) BH = Задержка включения режима автоповтора |
Регистры на выходе: |
Не используются |
Период автоповтора задается следующим образом:
Содержимое регистра BL |
Период автоповтора |
0 |
30,0 |
1 |
26,7 |
2 |
24,0 |
4 |
20,0 |
8 |
15,0 |
0Ah |
10,0 |
0Dh |
9,2 |
10h |
7,5 |
14h |
5,0 |
1Fh |
2,0 |
Для задержки включения режима автоповтора вы можете указывать следующие значения:
Содержимое регистра BH |
Задержка включения режима автоповтора, mc |
0 |
250 |
1 |
500 |
2 |
750 |
3 |
1000 |
В качестве примера приведем два фрагмента программы. Первый фрагмент увеличивает быстродействие клавиатуры до его верхнего предела, второй восстанавливает исходные значения временных характеристик.
union REGS rg; . . . rg.h.al = 5; rg.h.ah = 3; // Устанавливаем максимальное быстродействие клавиатуры rg.h.bl = 0; rg.h.bh = 0; int86(0x16, &rg, &rg); . . . // Восстанавливаем исходное быстродействие клавиатуры rg.h.bl = 0xa; rg.h.bh = 1; int86(0x16, &rg, &rg);
С помощью функции 05h можно вставить символы в буфер клавиатуры, как будто они были введены оператором.
Регистры на входе: |
AH = 05h; CL = код ASCII записываемого символа; CH = скан-код записываемого символа, или 0 |
Регистры на выходе: |
AL = 0 - запись выполнена успешно; AL = 1 - буфер клавиатуры переполнен |
Приведенная ниже фрагмент программы записывает в буфер клавиатуры пять символов '*'. Если запустить программу, соедржащую этот фрагмент кода, а затем посмотреть на системное приглашение, то вы увидите что-нибудь похожее на C:\>*****.
union REGS rg; int i; for(i=0; i<5; i++) { rg.h.ah = 5; rg.h.cl = '*'; rg.h.ch = 9; int86(0x16, &rg, &rg); }
Функция 10h, предназначенная для чтения символа с ожиданием, полностью аналогична функции 00h, но она может работать только с клавиатурой, имеющей 101 клавишу.
Приведем формат вызова функции:
Регистры на входе: |
AH = 10h; |
Регистры на выходе: |
AL = код ASCII символа или 0, если AH содержит расширенный код ASCII символа; AH = скан-код или расширенный код ASCII символа, если AL=0 |
Функция определена для BIOS, изготовленной после 15 декабря 1985 года.
Функция 11h полностью аналогична функции 01h, но она предназначена для работы с клавиатурой, имеющей 101 клавишу:
Регистры на входе: |
AH = 11h |
Регистры на выходе: |
ZF = 0, если в буфере имеется код нажатой клавиши; ZF = 1, если буфер клавиатуры пуст; AL = код ASCII символа или 0, если AH содержит расширенный код ASCII символа; AH = скан-код или расширенный код ASCII символа, если AL=0 |
Эта функция определена для BIOS, изготовленной после 15 декабря 1985 года.
Функция 12h возвращает в регистре AL состояние переключающих клавиш, таких как <Shift>, <Control>, <Alt>, <ScrollLock>, <NumLock>, <CapsLock>, <Insert> и используется только для 101-клавишных клавиатур:
Регистры на входе: |
AH = 12h |
Регистры на выходе: |
AL = Байт состояния переключающих клавиш |
Эта функция определена для BIOS, изготовленной после 15 декабря 1985 года.
Клавиатура современного компьютера, имеющая 101-клавишу, может работать в одном из трех режимов. Эти режимы различаются тем, как клавиатура посылает скан-коды в компьютер, когда пользователь нажимает и отпускает клавиши.
Первый режим – это режим совместимости с IBM PC/XT. В этом режиме скан-коды, посылаемые клавиатурой при нажатии клавиш, соответствуют приведенным нами в разделе «Средства BIOS для работы с клавиатурой». Когда пользователь нажимает клавишу, в компьютер посылается однобайтовый скан-код этой клавиши. Когда же пользователь отжимает клавишу, в компьютер посылается скан-код этой клавиши с установленным в единицу старшим битом.
Второй режим устанавливается по умолчанию после включения питания. От первого режима он отличается тем, что когда пользователь отжимает клавишу, в компьютер посылается вначале код 0F0h, а затем скан-код отжатой клавиши.
В третьем режиме каждой клавише присваивается собственный 8-разрядный код нажатия. Код, который передается при отжатии клавиши, состоит из двух байтов – байта 0Fh и байта кода нажатия. Другая особенность этого режима заключается в том, что коды, посылаемые любыми клавишами, не зависят от состояния других клавиш.
Едва ли вам потребуется изменять режим работы клавиатуры. Тем не менее, мы покажем, как это можно сделать, программируя контроллер клавиатуры.
Ниже мы приведем команды и параметры, которые нужно посылать контроллеру клавиатуры для установки описанных выше режимов работы:
Режим |
Команда |
Параметр |
1 |
0F0h |
01h |
2 |
0F0h |
02h |
3 |
0F0h |
03h |
К сожалению, MS-DOS не предоставляет программам каких-либо существенных дополнительных возможностей по сравнению с функциями прерывания BIOS INT 16h. Поэтому многие программы работают с клавиатурой через BIOS.
Однако если ваша программа пользуется клавиатурными функциями MS-DOS, то ей доступно средство переназначения ввода операционной системы. Это возможно благодаря тому, что клавиатурные функции MS-DOS являются функциями, работающими со стандартным вводом MS-DOS, а стандартный ввод может быть переназначен.
Кроме того, некоторые клавиатурные функции автоматически посылают введенные символы на устройство стандартного вывода. По умолчанию это дисплей, но устройство стандартного вывода может быть переназначено для вывода в файл, на принтер или другое устройство.
Вообще говоря, клавиатурные функции MS-DOS больше всего подходят для тех программ, которые ведут с оператором построчный диалог. Для таких программ при использовании средств переназначения ввода/вывода возможна организация автоматического пакетного выполнения, когда все сообщения выводятся в файл, а все данные, которые обычно вводятся с клавиатуры, считываются из заранее подготовленного файла "ответов".
Некоторые клавиатурные функции MS-DOS отслеживают комбинации клавиш <Control+C> и <Control+Break>. Если оператор ввел такую комбинацию клавиш, вызывается прерывание INT 23h, завершающее работу текущей программы. Если ваша программа не должна завершаться при нажатии этих комбинаций клавиш, можно либо создать и подключить собственный обработчик для INT 23h, либо использовать те клавиатурные функции MS-DOS, которые не выполняют проверку указанных выше комбинаций клавиш.
Приведем подробное описание клавиатурных функций прерывания MS-DOS INT 21h.
Функция 01h читает символы со стандартного устройства ввода. Если стандартным устройством ввода является клавиатура, и буфер клавиатуры пуст, выполнение программы задерживается до нажатия на любую клавишу.
Введенный символ выводится на стандартное устройство вывода.
Приведем формат вызова функции:
Регистры на входе: |
AH = 01h |
Регистры на выходе: |
AL = код ASCII символа или 0. Если регистр содержит 0, то следующий вызов этой же функции возвратит в регистре AL расширенный код ASCII символа Функция проверяет комбинации клавиш <Control+C> и <Control+Break> |
Если программа в качестве ASCII-кода получила 0, она должна вызвать эту функцию еще один раз. Во второй раз регистр AL будет содержать расширенный ASCII-код нажатой клавиши.
Функция 08h аналогична предыдущей функции с номером 01h. Она читает символы со стандартного устройства ввода. Если стандартным устройством ввода является клавиатура, и буфер клавиатуры пуст, выполнение программы задерживается до нажатия на любую клавишу.
Регистры на входе: |
AH = 08h |
Регистры на выходе: |
AL = код ASCII символа или 0. Если регистр содержит 0, то следующий вызов этой же функции возвратит в регистре AL расширенный код ASCII символа Функция проверяет комбинации клавиш <Control+C> и <Control+Break> |
Эту функцию необходимо использовать в тех случаях, когда не требуется автоматически дублировать на экране введенные с клавиатуры символы. Например, с ее помощью можно организовать ввод паролей.
Функция 07h читает символы со стандартного устройства ввода. Если стандартным устройством ввода является клавиатура, и буфер клавиатуры пуст, выполнение программы задерживается до нажатия на любую клавишу. Однако в отличие от функции 01h данная функция не проверяет комбинации клавиш <Control+C> и <Control+Break>.
Регистры на входе: |
AH = 07h |
Регистры на выходе: |
AL = код ASCII символа или 0. Если регистр содержит 0, то следующий вызов этой же функции возвратит в регистре AL расширенный код ASCII символа Функция не проверяет комбинации клавиш <Control+C> и <Control+Break> |
Ее использовать в тех случаях, когда завершение программы по нажатию указанных комбинаций клавиш по тем или иным причинам нежелательно. Например, программа держит в оперативной памяти буферы для данных, которые перед завершением работы обязательно должны быть записаны на диск. Если пользователь в неподходящий момент времени нажал комбинацию клавиш <Control+Break> и программа аварийно завершила работу, содержимое буферов будет потеряно.
Функция 06h может использоваться как для ввода с консоли, так и для вывода символов на консоль. Режим работы функции зависит от содержимого регистра DL при вызове функции. Если в этом регистре находится значение 0FFh, функция выполняет ввод с консоли, в противном случае символ, код которого записан в этот регистр, выводится на консоль.
Регистры на входе: |
AH = 06h DL = 0FFh - для ввода символа с консоли; или DL = код символа, не равный 0FFh - для вывода символа на консоль |
Регистры на выходе: |
ZF = 0, если в буфере имеется код нажатой клавиши; ZF = 1, если буфер клавиатуры пуст; AL = код ASCII символа или 0, если AH содержит расширенный код ASCII символа; AH = скан-код или расширенный код ASCII символа, если AL=0 Функция проверяет комбинации клавиш <Control+C> и <Control+Break> |
Очевидно, что с помощью этой функции нельзя вывести на консоль символ с кодом 0FFh.
Основное отличие функции 06h от всех описанных ранее заключается в том, что эта функция не ожидает, пока пользователь нажмет на клавишу. Если буфер клавиатуры пуст, функция просто устанавливает флаг процессора ZF. Если же в буфере клавиатуры имеются символы, флаг ZF сбрасывается и в регистр AL функция записывает код ASCII символа.
Функция 0Ah предназначена для ввода с клавиатуры строки символов:
Регистры на входе: |
AH = 0Ah DS:DX = адрес буфера для ввода строки |
Регистры на выходе: |
Буфер содержит введенную строку Функция проверяет комбинации клавиш <Control+C> и <Control+Break> |
Перед вызовом функции необходимо специальным образом подготовить буфер, адрес которого передается в регистрах DS:DX - в первый байт буфера следует записать максимальную длину max вводимой строки (в диапазоне от 1 до 244).
После возврата из функции первый байт буфера останется без изменений, а во второй байт будет записана длина введенной строки без учета завершающего ввод символа возврата каретки.
Ввод осуществляется до тех пор, пока либо количество введенных символов не достигнет max-1, либо пока не будет нажата клавиша <Enter> с кодом 0Dh. Если оператор уже ввел max-1 символ и продолжает вводить символы дальше, функция выдает звуковой сигнал и игнорирует вводимые символы до тех пор, пока не будет нажата клавиша <Enter>.
При вводе строки можно использовать стандартные средства редактирования MS-DOS, используемые при вводе команд в режиме командной строки.
Функция 0Bh проверяет состояние клавиатурного буфера. Вы можете вызывать ее перед функциями 01h, 07h, 08h для того, чтобы избежать ожидания нажатия на клавишу.
Регистры на входе: |
AH = 0Bh |
Регистры на выходе: |
AL = 0FFh, если в буфере имеется код нажатой клавиши; AL = 0, если буфер клавиатуры пуст. Функция проверяет комбинации клавиш <Control+C> и <Control+Break> |
Если ваша программа выполняет какую-либо длительную обработку (копирование файлов, форматирование дисков и так далее), вы можете вызывать эту функцию в процессе обработки для того чтобы пользователь мог прервать процесс.
Функция 0Ch очищает клавиатурный буфер, затем вызывает клавиатурную функцию MS-DOS, номер которой определяется содержимым регистра AL.
Регистры на входе: |
AH = 0Сh AL = 1, 6, 7, 8 или 0Ah |
Регистры на выходе: |
Не опеределены |
Если же регистр AL содержит другое значение, кроме приведенных выше, функция просто сбрасывает содержимое буфера и не выполняет никаких других действий.
Эту функцию удобно использовать тогда, когда перед вводом символа необходимо убедиться в том, что буфер клавиатуры пуст.
Стандартные библиотеки C содержат набор функций, предназначенных для работы с клавиатурой. Эти функции повторяют и немного дополняют возможности функций MS-DOS и BIOS, обслуживающих клавиатуру.
Самые простые из функций стандартной библиотеки С, предназначенных для работы с клавиатурой - getch и getche. Они описаны в файле conio.h.
Функция getch имеет следующий прототип:
int getch(void);
Эта функция возвращает код ASCII символа, прочитанного из клавиатурного буфера, причем прочитанный символ не отображается на экране. Если была нажата функциональная клавиша или клавиша перемещения курсора, функция возвращает 0. В этом случае функцию надо вызвать еще раз для получения расширенного кода ASCII нажатой клавиши.
Функция обрабатывает клавиши <Control+C> и <Control+Break> - при вводе этих комбинаций клавиш работа программы завершается.
Если клавиатурный буфер пуст, программа переводится в состояние ожидания.
Функция getche полностью аналогична функции getch, за исключением того, что прочитанный символ отображается на экране. Приведем прототип функции getche:
int getche(void);
Приведем исходные тексты программы KBDASCII, отображающей на экране коды ASCII и расширенные коды ASCII нажимаемых клавиш (листинг 2.4).
Листинг 2.4. Файл kbdascii\kbdascii.c
// ===================================================== // Просмотр клавиатурных кодов ASCII // // (C) Фролов А.В, 1997 // // E-mail: frolov@glas.apc.org // WWW: http://www.glasnet.ru/~frolov // или // http://www.dials.ccas.ru/frolov // ===================================================== #include <conio.h> #include <ctype.h> #include <stdio.h> int main(void) { int key; printf("KBDASCII, (c) A. Frolov, 1997\n" "Press any key, <Esc> to exit\n"); // Читаем в цикле символы с клавиатуры и отображаем // коды ASCII нажатых клавиш. // Выходим из цикла, когда пользователь нажимает // клавишу <Esc> for(;;) { // Читаем символ key = getch(); // Если прочитанный символ равен 0, вызываем функцию // getch для получения расширенного // кода ASCII нажатой клавиши if((key == 0) || (key == 0xe0)) { key = getch(); printf("Extended code ASCII:\t" ); } else printf( "Code ASCII:\t"); printf("%d\n",key); // Когда пользователь нажимает клавишу // <Esc>. выходим из цикла if(key == 27) break; } return 0; }
Для проверки буфера клавиатуры на наличие символов можно использовать функцию. Она также описана в файле conio.h:
int kbhit(void);
Если буфер клавиатуры не пуст, функция возвращает ненулевое значение. В этом случае программа может прочитать символы из буфера клавиатуры при помощи фукнкций getch и getche. Если буфер клавиатуры пуст, функция возвращает нулевое значение.
Приведем исходный текст программы KBDHIT (листинг 2.5), ожидающей, когда пользователь нажмет на любую клавишу. Во время ожидания программа выводит на экран поочередно символы "<" и ">".
Листинг 2.5. Файл kbdhit\kbdhit.c
// ===================================================== // Демонстрация применения функции kbhit // // (C) Фролов А.В, 1997 // // E-mail: frolov@glas.apc.org // WWW: http://www.glasnet.ru/~frolov // или // http://www.dials.ccas.ru/frolov // ===================================================== #include <stdio.h> #include <conio.h> int main(void) { int key; // Ожидаем нажатия на любую клавишу. // Во время ожидания выводим на экран поочередно // символы "<" и ">" while(!kbhit()) printf("<\b>\b"); // Как только будет нажата какая-нибудь клавиша, // выводим ее ASCII-код key = getch(); // Если прочитанный символ равен 0, вызываем // функцию getch() для получения расширенного // кода ASCII нажатой клавиши if( (key == 0) || (key == 0xe0) ) { key = getch(); printf( "Extended code ASCII:\t" ); } else printf( "Code ASCII:\t"); printf("%d\n",key); return 0; }
Для ввода с клавиатуры строки символов можно использовать функцию cgets, работающую аналогично функции 0Ah прерывания MS-DOS INT 21h:
char *cgets(char *buffer);
Функция cgets описана в файле conio.h.
Перед вызовом cgets аргумент функции buffer должен указывать на массив, размер которого должен быть достаточным для хранения вводимой строки, завершающего строку нулевого байта и двух дополнительных байтов. Первый элемент массива buffer[0] должен содержать максимальную длину вводимой строки - как и для функции 0Ah прерывания MS-DOS INT 21h.
После завершения ввода второй элемент массива buffer[1] будет содержать длину введенной строки, сама строка будет завершаться символами новой строки NL, перевода строки LF и нулем.
Функция cgets возвращает указатель на начало введенной строки в буфере, то есть на третий элемент массива buffer[2].
В следующем фрагменте программы функция cgets используется для ввода целого числа:
#define MAX 80 char buf[MAX]; . . . int i; char *bufptr; // Устанавливаем максимально допустимую длину строки buf[0] = MAX + 2; printf("\nВведите целое число: "); // Вводим число, можно использовать клавиши редактирования bufptr = cgets(buf); // Преобразуем введенное число к формату int // и выводим его i = atoi(bufptr); printf("\nВы ввели число %d", i);
Существует и более удобная по сравнению с cgets функция, предназначенная для ввода строки с клавиатуры, а точнее, из стандартного потока ввода. Это функция gets:
char *gets(char *buffer);
Функция gets описана в файле stdio.h.
Эта функция читает строку из стандартного потока ввода stdin и запоминает ее в буфере buffer. Символ новой строки \n в конце введенной строки функция заменяет на нуль. После завершения ввода функция возвращает указатель на заполненный буфер или NULL в случае ошибки или условия "Конец файла".
Обратим ваше внимание на отличия между функциями cgets и gets:
· Функция cgets позволяет редактировать вводимую строку символов, функция gets просто записывает в буфер все символы подряд (в том числе и коды клавиш редактирования).
· Программе, использующей для ввода с клавиатуры функцию cgets, недоступны средства переназначения ввода операционной системы. Если же программа использует функцию gets, которая читает строку из стандартного потока ввода, можно использовать средства переназначения.
· Перед вызовом функции cgets необходимо специальным образом подготовить буфер для вводимой строки (записать в первый байт буфера длину вводимой строки). Функция gets не требует никакой подготовки буфера.
Еще одна полезная функция, которую можно использовать для ввода с клавиатуры - scanf. Эта функция подробно описана во всех книгах по языку программирования Си, поэтому мы не будем ее подробно рассматривать. Отметим только, что с помощью этой функции можно организовать ввод чисел в заданном формате. Однако можно сначала ввести строку при помощи функций cgets или gets, а уже потом выполнять все необходимые проверки и преобразования этой строки.