Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Задача 2. Записать в буфер клавиатуры последовательность символов согласно выбранному

Читайте также:
  1. В. Г. Белинский о воспитании, возрастных особенностях детей и воспитательных задачах детской литературы
  2. Вопрос 19. Задача синтеза СУ на стадии ТЗ. Классификация методов параметрического синтеза АСР
  3. Глава 2. Задача и цель псалмов.
  4. Если задача не требует незамедлительного решения, сформулируйте ее, отложите и переключите свое внимание в ближайшие недели на другие сферы жизни.
  5. Задача 1
  6. Задача 1
  7. Задача 1

Условие:

 

Записать в буфер клавиатуры последовательность символов согласно выбранному варианту тремя способами (три программы на языке Си): с использованием функции 5 прерывания 16h, осуществляя непосредственный доступ к ячейкам памяти, выделенным под буфер клавиатуры, по текущему значению указателя "головы" буфера; то же, но по текущему указателю "хвоста" буфера.

 

Поместить в буфер клавиатуры последовательность кодов символов и код <Enter>, позволяющих после окончания работы программы удалить её исполняемый файл, предполагая, что он находится в текущем каталоге.

 

Способ 1:

С использованием функции 5 прерывания 16h

 

Листинг программы:

 

#include <io.h>

#include <dos.h>

#include <process.h>

#include <conio.h>

#include <stdio.h>

#include <fcntl.h>

#include <sys\types.h>

#include <sys\stat.h>

#include <errno.h>

 

main()

{

union REGS rg;

int i;

 

rg.h.ah = 5;

rg.h.cl = 'd';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl ='e';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl = 'l';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl =' ';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl ='2';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl ='_';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl ='3';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl ='.';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl ='e';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl ='x';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl ='e';

rg.h.ch = 0;

int86(0x16, &rg, &rg);

 

rg.h.ah = 5;

rg.h.cl = 00;

rg.h.cl = 0x1c;

int86(0x16,&rg, &rg);

system ("c:\\nc\\nc.exe");

return 0;

 

}


Пояснительная записка к задаче 2 (способ 1):

 

Набор функций для работы с клавиатурой, предоставляемый в распоряжение программиста прерыванием BIOS INT 16h, включает в себя функции для выборки кода нажатого символа из буфера с ожиданием нажатия, функции для проверки содержимого буфера и для управления содержимым буфера, функции для изменения скоростных характеристик клавиатуры.

 

С помощью функции 05h (прерывание 16h) можно вставить символы в буфер клавиатуры, как-будто они были введены оператором.

 

Регистры на входе: 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);

}

Для определения скан-кодов и кодов ASCII нажимаемых клавиш использовалась следующая программа:

 

#include <stdio.h>

#include <dos.h>

 

int main(void)

{

union REGS rg;

 

printf("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;

}

 

Буфер клавиатуры

Буфер клавиатурыимеет длину 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 для выполнения практически всех клавиатурных операций.


Способ 2: по текущему значению указателя "головы" буфера

Способ 3: по текущему значению указателя "хвоста" буфера

 

Листинги программ:

 

#include <io.h>

#include <dos.h>

#include <process.h>

#include <conio.h>

#include <stdio.h>

#include <fcntl.h>

#include <sys\types.h>

#include <sys\stat.h>

#include <errno.h>

#define KB_BUFFER_START 0x1e /* Смещение начала буфеpа клавиатуpы */

#define KB_BUFFER_END 0x3e /* Смещение конца буфеpа клавиатуpы */

#define HEAD_PTR 0x1a /* Смещение указателя "головы" */

#define TAIL_PTR 0x1c /* Смещение указателя "хвоста" */

#define OK 0 /* Код нажатия записан в буфеp */

#define FULL 1 /* Буфеp клавиатуpы заполнен до пpедела */

/* Записать один символ в буфер клав-ры с "хвоста" */

int enter_kbt(unsigned key_code)

{unsigned register _es *head=(unsigned _es *) HEAD_PTR,

_es *tail=(unsigned _es *) TAIL_PTR,

_es *tmp,ret;

_ES=0x40;

disable(); /* Начало кpитической секции кода */

tmp=(unsigned _es *) *head;

if(tmp==(unsigned _es *)KB_BUFFER_START)

/* "Пеpескок" указателя на конец буфеpа */

tmp=(unsigned _es *)KB_BUFFER_END;

if(tmp-1==(unsigned _es *)*tail) /* Буфеp полон */

ret=FULL;

else

{ *(unsigned _es *)tmp=key_code;

tmp--;

*head=(unsigned)tmp;

ret=OK; }

enable(); return ret;

}

 

int main()

{

unsigned key_codes[]={0x4200,0x1c00};

/* В массиве key_codes[]все перечисленой в первом варианте*/

FILE *iii;

int source, taget, i;

char *buffer;

int count;

while(kbhit()) getch(); /* Очистка буфеpа клавиатуpы */

/* Запись в буфеp клавиатуpы массива key_codes с "головы". */

for(i=1;i>-1;i--)

{

enter_kbt(key_codes[i]);

}

system("c:\\nc\\nc.exe");

}

 

 

 

#include <io.h>

#include <dos.h>

#include <process.h>

#include <conio.h>

#include <stdio.h>

#include <fcntl.h>

#include <sys\types.h>

#include <sys\stat.h>

#include <errno.h>

#define KB_BUFFER_START 0x1e /* Смещение начала буфеpа клавиатуpы */

#define KB_BUFFER_END 0x3e /* Смещение конца буфеpа клавиатуpы */

#define HEAD_PTR 0x1a /* Смещение указателя "головы" */

#define TAIL_PTR 0x1c /* Смещение указателя "хвоста" */

#define OK 0 /* Код нажатия записан в буфеp */

#define FULL 1 /* Буфеp клавиатуpы заполнен до пpедела */

/* Записать один символ в буфер клав-ры с "хвоста" */

int enter_kbt(unsigned key_code)

{unsigned register _es *tail=(unsigned _es *) TAIL_PTR,

_es *head=(unsigned _es *) HEAD_PTR,

_es *tmp,ret;

_ES=0x40;

disable(); /* Начало кpитической секции кода */

tmp=(unsigned _es *) *tail;

if(tmp==(unsigned _es *)KB_BUFFER_END)

/* "Пеpескок" указателя на начало буфеpа */

tmp=(unsigned _es *)KB_BUFFER_START;

if(tmp+1==(unsigned _es *)*head) /* Буфеp полон */

ret=FULL;

else

{ *(unsigned _es *)tmp=key_code;

tmp++;

*tail=(unsigned)tmp;

ret=OK; }

enable(); return ret;

}

 

int main()

{

unsigned key_codes[]={0x4200,0x1c00};

/* В массиве key_codes[]все перечисленой в первом варианте*/

FILE *iii;

int source, taget, i;

char *buffer;

int count;

while(kbhit()) getch(); /* Очистка буфеpа клавиатуpы */

/* Запись в буфеp клавиатуpы массива key_codes с "хвоста". */

for(i=0;i<2;i++)

{

enter_kbt(key_codes[i]);

}

system("c:\\nc\\nc.exe");

}

 

 

Пояснительная записка к задаче 2 (способы 2 и3):

 

Буфер клавиатуры организуется, как кольцевая очередь, доступ к которой осуществляется с помощью указателя "головы": (head pointer), адрес которого 40h:1Ah, и указателя "хвоста" с адресом 40h:1Ch. Указатель "хвоста" задаёт смещение, где будет записан обработчиком прерывания 9 двухбайтовый код буферизуемой клавиши. Указатель "головы" задаёт смещение возвращаемого слова по запросу операционной системы или BIOSа. Буфер клавиатуры занимает 32 байта памяти с адреса 40h:1Eh до 40h:3Eh. Если значения указателей "головы" и "хвоста" равны между собой, то буфер пуст.

В приведенном листинге функция int enter_kbt(unsigned key_code) вводит в первом случае с «головы», во втором с «хвоста» в буфер клавиатуры символ key_code.

Используются переменные tail, head, tmp типа register unsigned _es *. tail - это адрес, по которому хранится адрес "хвоста"; head - адрес, содержащий адрес "головы"; tmp - значение * tail указателя "хвоста" в способе 3 и значение * head указателя «головы» в способе 2, преобразованное к виду (unsigned _es *). В случае, когда tmp указывает на конец буфера, то ему присваивается значение на начало буфера и наоборот. Поэтому значение указателя "хвоста" может быть и меньше значения указателя "головы" и наоборот.

Если (для способа 3) tmp+1=(unsigned _es *)*head, то буфер полон и происходит выход из функции.

Если (для способа 2) tmp-1=(unsigned _es *)*tail, то буфер полон и происходит выход из функции.


Дата добавления: 2015-10-16; просмотров: 69 | Нарушение авторских прав


Читайте в этой же книге: Главная загрузочная запись | Первичный и расширенный раздел | Формат загрузочной записи | Прерывания INT 25h и INT 26h | Инициализация резидентной программы |
<== предыдущая страница | следующая страница ==>
Найти физический номер дисковода.| Создать резидентную программу, которая выводит на терминал слово "else" по нажатию Alt.

mybiblioteka.su - 2015-2024 год. (0.032 сек.)