CFA LogoCFA Logo Computer
Новости Статьи Магазин Драйвера Контакты
Новости
RSS канал новостей
В конце марта компания ASRock анонсировала фирменную линейку графических ускорителей Phantom Gaming. ...
Компания Huawei продолжает заниматься расширением фирменной линейки смартфонов Y Series. Очередное ...
Компания Antec в своем очередном пресс-релизе анонсировала поставки фирменной серии блоков питания ...
Компания Thermalright отчиталась о готовности нового высокопроизводительного процессорного кулера ...
Компания Biostar сообщает в официальном пресс-релизе о готовности флагманской материнской платы ...
Самое интересное
Программаторы 25 SPI FLASH Адаптеры Optibay HDD Caddy Драйвера nVidia GeForce Драйвера AMD Radeon HD Игры на DVD Сравнение видеокарт Сравнение процессоров

АРХИВ СТАТЕЙ ЖУРНАЛА «МОЙ КОМПЬЮТЕР» ЗА 2003 ГОД

Мысли о Паскале

Владислав ДЕМЬЯНИШИН nitromanit@mail.ru

Продолжение, начало см. в МК №46, 51-52, 4, 6-7, 10, 12-13, 16-18, 22, 24, 29, 34, 41, 46, 4, 6 (165, 170-171, 175, 177-178, 181, 183-184, 187-189, 193, 195, 200, 205, 212, 217, 227, 229).

Запряжем клаву

Сегодня поговорим о клавиатуре, а вернее, о том, как получать информацию, введенную с клавиатуры. Конечно, в языке Turbo Pascal есть стандартные функции KeyPressed:boolean и ReadKey:char, но пользоваться ими хлопотно: чтобы узнать, была ли нажата клавиша, необходимо постоянно вызывать первую, и если она возвращает true, то следует вызвать и вторую для получения кода нажатой клавиши. При этом следует проверить полученный символ на равенство #0, и если равенство не выполняется, то это значит, что была нажата символьная клавиша. Ну а если все же равенство выполняется, то необходимо вызвать еще раз стандартную функцию ReadKey, чтобы получить символ, соответствующий нажатой в данный момент специальной клавише, коей может быть и любая функциональная клавиша, и клавиши управления курсором. При этом следует знать, что клавиши Enter, Tab и BackSpace отнесены к символьным клавишам, т.е. после первого вызова ReadKey будет возвращен символ, соответствующий этим клавишам, т.е. #13, #9, #8 соответственно. Используя этот способ получения информации с клавиатуры необходимо учесть тот факт, что символьные и специальные клавиши могут иметь одинаковые значения типа Char, что может внести путаницу при идентификации нажатой клавиши. Да и сама реализация проверки нажатия и получения кода нажатой клавиши получится несколько громоздкой.

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

А что если описать свою функцию, которая бы в результате вызова своим единственным возвращаемым результатом сразу давала бы знать, нажата ли какая-нибудь клавиша и какая именно нажата? При этом чтобы каждой клавише соответствовал бы уникальный код, который можно было бы применять в конструкциях условных операторов. Используя этот метод, можно будет легко сепарировать коды специальных и функциональных клавиш от символьных клавиш, т.е. сортировать их по функциональному признаку, что очень удобно, и без запутанных чтений расширенного кода клавиатуры, как это требуется при использовании стандартной функции ReadKey.

Если вы со мной согласны, то давайте начнем формировать код нашего нового модуля KEYBOARD.PAS. Для начала оформим заголовок модуля и опишем константы для наиболее необходимых кодов клавиш. Следуя традиции Windows называть коды клавиш как виртуальные клавиши (VK — Virtual Key), я предлагаю для имен констант, соответствующих клавишам, использовать префикс VK_. Таким образом, если понадобится переносить Pascal-программу на Delphi, то в этом смысле проблем не возникнет — там, за немногими исключениями, приняты константы с аналогичными именами.

В виду того, что константы, выстроенные в столбик, займут много строк, а место под статью ограничено, я разместил десятичные константы в таблице, чтобы сэкономить место. А вы уж сами перепишите их в модуль столбиком или скачайте весь модуль целиком с http://amonit.boom.ru — если, конечно, у вас имеется доступ в Интернет. Да, не за горами тот день, когда страницы журналов будут скроллируемыми и не будут рваться как бумага, так как будут из эластичной полимерной пленки с изменяемой контрастностью. А еще лучше, если журнал будущего будет иметь гнездо USB или хотя бы PCMCIA, чтобы можно было сразу применить его содержимое, а не бить руками клавиатуру, набирая ссылки, цитаты, сводные таблицы, примеры исходного кода программ и т.д. Что-то меня занесло не туда. Так о чем это я? Ах да…

Теперь можно приступить к написанию функций.

Функция InKeys предназначена для внутреннего использования, поэтому нет нужды ее заголовок помещать в блок interface. Ее код основан на вызове стандартной функции MS-DOS для получения кода нажатой клавиши без ожидания и без вывода ее на экран, к тому же она совсем не реагирует на Ctrl+Break. Для вызова этой функции MS-DOS необходимо в регистр AH записать номер функции 6, затем в регистр DL надо поместить значение $0FF. Функция активируется вызовом программного прерывания INT $21, и если при возврате из функции флаг нуля установлен в 1, то буфер клавиатуры пуст, т.е. с момента последнего вызова этой функции новых нажатий клавиш не поступало. Если флаг нуля сброшен в 0, то код нажатой клавиши, а вернее сказать, символ, соответствующий нажатой символьной клавише, содержится в регистре AL. При этом, если значение регистра AL равно нулю, значит, была нажата специальная клавиша, и ее код — его еще называют расширенным — следует получить посредством еще одного вызова INT $21.

Следует отметить, что функция InKeys проверяет буфер клавиатуры, и если он пуст, то она возвращает значение специальной пустой клавиши VK_KEYOFF=511, что значит, что нажатия клавиши не было. Если к моменту вызова функции InKeys произошло нажатие клавиши, то полученный код анализируется, и если этот код соответствует нажатию символьной клавиши, то функция возвращает код соответствующего символа, т.е. результат колеблется в пределах 0..255, и его затем легко преобразовать в тип Char. В том случае, когда нажата специальная клавиша, то функция запрашивает ее расширенный код и прибавляет к нему число 256, в итоге значения кодов для специальных клавиш будут варьироваться в пределах 256..510.

Таблица   Таблица

Следующая функция InKey предназначена для внешнего использования и возвращает код нажатой клавиши подобно тому, как об этом сказано в предыдущем абзаце. Правда, данная функция для большего удобства преобразует коды клавиш Esc, Enter, BackSpace и Tab из символьных в специальные.

Имея такую функцию, легко сконструировать некоторый процесс, который должен завершаться при нажатии на клавишу Esc:

И чтобы снова и снова не изобретать велосипед, опишем функцию WaitKey, которая ждет нажатия клавиши, чтобы вернуть ее код:

Например, может понадобиться выдать сообщение Прервать работу программы и выйти в систему?(Y/N) и дождаться ответа от пользователя:

Собственно, функции InKey и WaitKey предоставляют исчерпывающий сервис для осуществления управления программой с клавиатуры. Читатели, которые знакомы хотя бы с классическим Бейсиком, наверняка заметили в названии функции InKey что-то до боли знакомое. Совершенно верно, я позаимствовал этот идентификатор из языка программирования Бейсик, ведь я из того поколения программистов, которые с этого языка начинали.

Но при разработке программ может понадобиться осуществить интенсивный опрос клавиатуры, и чтобы это сделать, может пригодиться функция

которая позволяет управлять задержкой Delay перед первым повторением нажатия клавиши, и автоповтор Rate нажатия клавиши при удержании клавиши в нажатом состоянии. Следует, что если установить оба параметра функции SetKeySpeed в 0, получим максимально быстрый ввод с клавиатуры, что будет кстати в текстовом редакторе или в игре.

Таблица   Таблица

Рискну предположить, что кому-то может понадобиться манипулировать светодиодами на панели клавиатуры — чтобы устроить себе примитивную светомузыку :-) или при написании собственного драйвера клавиатуры. Для управления светодиодами клавиатуры существует двухбайтная команда $0ED, которую следует послать контроллеру клавиатуры (микросхема микропроцессора Intel 8042), затем дождаться готовности контроллера и послать байт-маску светодиодов, где бит 0, равный 1 включает индикатор ScrollLock, установленный бит 1 включает индикатор NumLock, и бит 2, соответственно, —CapsLock. Остальные биты игнорируются. Если сбросить один из трех бит в 0, то соответствующий светодиод погаснет.

Итак, приступим к написанию процедуры SetLed:

Для посылки управляющей команды следует поместить ее код в регистр AL и послать его в порт $60, после этого дождаться момента, когда буфер очереди команд контроллера клавиатуры окажется пуст, что будет означать, что команда принята к исполнению и контроллер ожидает байт данных для последней команды. Готовность контроллера можно определить с помощью процедуры WaitChip8042, которая будет рассмотрена далее. Когда контроллер будет готов к приему байта данных, следует в регистр AL поместить байт-маску для светодиодов, структура которого рассматривалась выше, и послать его в порт $60.

Теперь рассмотрим процедуру WaitChip8042:

Она позволяет определить, готов ли контроллер клавиатуры к приему информации. Для этого достаточно организовать цикл, например, в $0FFFF итераций, в теле которого будет происходить чтение статуса контроллера (команда in al,64h) в регистр AL, затем производится проверка состояния бита готовности 1 байта статуса (команда test al,00000010b), и если бит сброшен в 0, то цикл прекращается, т.е. мы дождались своего часа :-).

Только при отладке программы не вздумайте выполнять процедуру SetLed в пошаговом режиме. При посылке контроллеру клавиатуры управляющей команды, за которой должен следовать байт данных, произойдет блокирование ввода с клавиатуры до того момента, пока не будет получен ожидаемый байт данных. Следовательно, очередное нажатие на клавишу F7 или F8 ни к чему не приведет, так как компьютер зависнет (или зависнет задача MS-DOS, если под Windows). Это происходит вследствие того, что контроллер клавиатуры работает в однозадачном режиме и поэтому, если занят приемом команды, то уж, конечно, не может сканировать состояние клавиш. Вот когда контроллеры клавиатуры станут многозадачными, вот тогда-то… :-)

В качестве примера послужит программка, зажигающая индикаторы клавиатуры:

(Продолжение следует)

Рекомендуем ещё прочитать:






Данную страницу никто не комментировал. Вы можете стать первым.

Ваше имя:
Ваша почта:

RSS
Комментарий:
Введите символы или вычислите пример: *
captcha
Обновить





Хостинг на серверах в Украине, США и Германии. © sector.biz.ua 2006-2015 design by Vadim Popov