Консультация № 162110
05.03.2009, 15:42
0.00 руб.
0 13 1
Как обработать отжатие клавиши клавиатуры? У меня есть в паскале массив с булевским типом. Кол-во елементов массива равно кол-ву интересующих меня клавиш. С нажатием клавиши все ясно, но как узнать какие отжаты

Обсуждение

давно
Посетитель
7438
7205
05.03.2009, 15:48
общий
ДОС ?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
05.03.2009, 16:14
общий
И использовать ассемблерную вставку? Или через intr?
Неизвестный
05.03.2009, 16:20
общий
Да, хочу использовать ассемблерную вставку только непонятно как использовать аппаратное прерывание
Неизвестный
05.03.2009, 16:21
общий
ДОС ?

да
Неизвестный
05.03.2009, 16:25
общий
перехвать прерывания 09h и ловить скан-коды
Неизвестный
05.03.2009, 16:32
общий
Я прочитал этот материал (http://www.codenet.ru/progr/asm/norton/10.php) и просмотрел некоторые статьи, но пока не нашел ответ на свой вопрос.

У меня есть в паскале массив с булевским типом

Возможно попытаюсь сделать функцию-предикат, которой в качестве параметра буду передавать литеру. Не суть важно.

Подскажите куда копать?
Я читал, что возникает аппаратное прерывание при отжатии клавиши, но материала не нашел в нужном кол-ве чтобы понять
Или можно это сделать через буфер клавиатуры?
Неизвестный
05.03.2009, 16:34
общий
перехвать прерывания 09h и ловить скан-коды


Это не сложно.
Вопрос как узнать какие клавиши отжаты
давно
Посетитель
7438
7205
05.03.2009, 16:39
общий
9-е прерывание приходит и по нажатию, и по отжатию клавиши.
Код читается из порта 60h.
Признак нажатия/отжатия - старший бит (маска 80h) : 0/1 - нажата/отжата
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
05.03.2009, 18:42
общий
Всем спасибо. Признаю, у меня туго с ассемблером.. Не понимаю, как обрабатывать (перехватывать, ловить etc) аппаратные прерывания.
Сделал по другому, в принципе на этом могу уже делать свою игрушку в дос

Код:
program AsmAndPas;
uses
crt;
var
ScanCode : byte;
shoot,left,right:boolean;
begin
clrscr;
repeat
asm
int 9h {???}
in al,60h
mov ScanCode,al
end;
case ScanCode of
28 : shoot:=true;
156 : shoot:=false;
30 : left:=true;
158 : left:=false;
32 : right:=true;
160 : right:=false;
end;
writeln(left);
writeln(shoot);
writeln(right);
until ScanCode=1;
writeln('End');
readln;
end.


давно
Старший Модератор
31795
6196
05.03.2009, 20:13
общий
Борисенко Сергей Владимирович:
Когда-то на паскале(почти ) писал резидентную программу
Код:
program q105873;
{&A-}
Var
b,c:word;
d:char;
e,f:^word;{указатели на переменную WORD}
{перевод числа в 16-ю систему}
function g(a:word):string;
var
b,c:integer;
d:string;
begin
d:='';
for b:=0 to 3 do
begin
c:=a mod 16;
if c>9 then c:=c+39;
d:=chr(c+48)+d;
a:=a div 16;
end;
g:=d;
end;
{наш обработчик}
procedure myInterrupt;
interrupt;
var
h:^byte;
d:byte;
begin
{прерывание INT3- один байт и без параметров, запускаем старый обработчик}
InLine($cc);
{получаем адрес начала и конца буфура клавиатуры}
e:=ptr($40,$1a);
f:=ptr($40,$1c);
if e^<>f^ then
begin
{получаем состояние клавиатуры}
h:=ptr($40,$17);
d:=h^;
{отделяем нажатие клавиши CTRL}
d:=d mod 16;
d:=d div 4;
if d >0 then
begin
{получаем нажатую клавишу}
c:=e^;
h:=ptr($40,c);
d:=h^;
{нажата клавиша "А"}
if d=1 then
begin
writeln;
{перебираем все прерывания}
for b:=0 to 255 do
begin
e:=ptr(0,4*b);
f:=ptr(0,4*b+2);
if(e^<>0)and(f^<>0)then
write(' ',g(b),':=',g(f^),':',g(e^));
end;
{записываем перевод строки}
h^:=3;{команда перевода строки: ^C будет всегда в конце вывода}
end;
end;
end;
end;
Begin
{для процедуры Keep(), запоминаем сегмент стека и сегмент PSP}
inline($1e/$16);
{перебираем все прерывания}
for b:=0 to 255 do
begin
{получаем смещение}
f:=ptr(0,(b*4));
{получаем сегмент}
e:=ptr(0,(b*4+2));
if (e^<>0)and(f^<>0)then
write(' ',g(b),':=',g(e^),':',g(f^));
end;
{GetIntVec(09)}
{получаем обработчик клавиатуры}
f:=ptr(0,36);
b:=f^;
{segment}
f:=ptr(0,38);
c:=f^;
{SetIntVec(03)}
{записываем старый обработчик на место прерывания INT3}
f:=ptr(0,12);
f^:=b;
{segment}
f:=ptr(0,14);
f^:=c;
{SetIntVec(09)}
{записываем смещение нашего обработчика}
c:=ofs(myInterrupt);
f:=ptr(0,36);
f^:=c;
{и сегмент}
c:=CSeg;
f:=ptr(0,38);
f^:=c;
{аналог процедуры Keep(),
но сделанный с помощью прерывания int 27
команды:
5A pop dx
58 pop ax
2B D0 sub dx,ax
C1 E2 04 shl dx,4
81 C2 4000 add dx,4000h
CD 27 int 27h
и места меньше занимает}
inline($5a/$58/$2b/$d0/$c1/$e2/$04/$81/$c2/0/$40/$cd/$27);
end.


Для Вас будет интерестно как установить обработчик.
Каждый раз когда происходит любое событие с определенным устройством, контролер устройства выдает сигнал на контролер прерываний, а тот в свою очередь на процессор. Получив сигнал - процессор считывает с таблицы прерываний адрес соответствующего обработчика и передает управление ему. Отработав данное событие обработчик возвращает управление в прерваную программу.
Если Вы будуте делать процедуру myIntrupt на ассемблере, то Вам нужно почти полностью повторить стандартный обработчик:
прочитать код с контролера клавиатуры и сообщить процессору, что обработка прерывания уже завершена, а также вернуть управление.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
06.03.2009, 17:14
общий
это ответ
Здравствуйте, Борисенко Сергей Владимирович!

Программа в приложении на ТР 7.0.
Устанавливается свой обработчик прерывания, который обрабатывает контролер клавиатуры и записывает в два логических массива значение истина или ложь, в зависимости от того какая клавиша нажата или отпущена.
Длина массивов выбрана 128 байт для обработки всех возможных скан-кодов, а в самой программе Вы используете только нужные.
Выход из цикла нажатая и отпущенная клавиша ESC. После этого востанавливается старый обработчик прерываний.
Вопросы задавайте в мини-форум.
Удачи!

Приложение:
uses
crt;
var
ArrayKeyUp,ArrayKeyDown:word;
ArrayUp,ArrayDown:array[0..127]of boolean;
Old09s,Old09o:word;
tempA,tempB:^word;
procedure myInterrupt;interrupt;
begin
asm
{запрещаем аппаратные прерывания}
cli
xor bx,bx{сбрасываем результат}
in al,60h{читаем сканкод}
shl al,1{получаем старший бит в флаг CF}
adc bx,0{суммируем с результатом}
xor ah,ah{сбрасываем старший байт}
shr al,1{востанавливаем сканкод клавиши}
mov si,ArrayKeyUp{указатель на логический массив отпущенных клавиш}
mov di,ArrayKeyDown{указатель на логический массив нажатых клавиш}
or bx,bx
jz @@001
xchg si,di{меняем указатели}
@@001:
mov bl,1{принудительно истина}
add si,ax{укуазатель на логическое значение клавиш}
mov [si],bh{записываем результат}
add di,ax{укуазатель на логическое значение клавиш}
mov [di],bl{записываем результат}
{стандартный выход из обработчика клавиатуры}
in al,61h
push ax
or al,80h
out 61h,al
pop ax
out 61h,al
mov al,20h
out 20h,al
sti{разрешаем прерывания}
end;
end;
begin
{сбрасываем логические массивы}
for old09o:=0 to 127 do
begin
ArrayUp[old09o]:=false;
ArrayDown[old09o]:=false;
end;
{получаем указатель на логический массив}
ArrayKeyUp:=ofs(ArrayUp);
ArrayKeyDown:=ofs(ArrayDown);
{устанавливаем указатель на нужный вектор таблицы прерываний и запоминаем старый обработчик}
tempA:=ptr(0,36);
old09o:=tempA^;{смещение обработчика}
tempB:=ptr(0,38);
old09s:=tempB^;{сегмент обработчика}
asm
cli{запрещаем прерывания}
end;
tempA^:=ofs(myInterrupt);{записываем своё смещение}
tempB^:=seg(myInterrupt);{записываем свой сегмент}
asm
sti{разрешаем прерывания}
end;
{сам цикл обработки клавиш}
repeat
clrscr;
writeln('a:',arrayUp[30]:7,'s:':4,arrayUp[31]:7,'d:':4,arrayUp[32]:7);
writeln('a:',arrayDown[30]:7,'s:':4,arrayDown[31]:7,'d:':4,arrayDown[32]:7);
delay(1000);
until ArrayUp[1];
{востанавливаем старый обработчик}
asm
cli{запрещаем прерывания}
end;
tempA^:=old09o;
tempB^:=old09s;
asm
sti{разрешаем прерывания}
end;
end.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
06.03.2009, 17:17
общий
Борисенко Сергей Владимирович:
Забыл добавить программа на ТР 7.0
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
07.03.2009, 00:23
общий
Забыл добавить программа на ТР 7.0

Спасибо под турбо и запускал, все понятно .
Форма ответа