I have the following code:
mov ah,01
int 21h
cmp al, 4bh
je apaga
If the user presses the left arrow key then I´m going to delete a square that I habe drawn. But the problem is that the left arrow key is equal to 4b00 and the right arrow key is equal to 4d00. That doesn't fit into al. So how can I solve this problem?
you should keep this in the same thread as the other posts
that way, i get notified if there is an update
replace the
cmp al,4Bh
with
cmp ax,4B00h
Hi,
DOS function 1, Console Input, will first return a zero when
used with a function key. You call it a second time to see
which function key it was.
MOV AH,1
INT 21H
CMP AL,0
JNZ NotFunc
MOV AH,1
INT 21H
CMP AL,4BH ; Left arrow?
JZ LeftArr
CMP AL,4DH ; Right arrow?
JZ RightArr
.....
Regards,
Steve N.
in his other thread, i gave him a nice little proc to do that :bg
Small keyboard handle routines for scancode keys from peter norton´s assembly book:
CHECK_KEYBOARD_INPUT PROC NEAR
PUSH AX
MOV AH,0Bh
INT 21h
OR AL,AL
JZ NO_INPUT
CALL READ_KEYBOARD_INPUT
NO_INPUT:
POP AX
RET
CHECK_KEYBOARD_INPUT ENDP
################
READ_KEYBOARD_INPUT PROC NEAR
MOV AH,7h
INT 21h
OR AL,AL
JNZ NO_SCANCODE
INT 21h
CALL HANDLE_KEYBOARD_INPUT
NO_SCANCODE:
RET
READ_KEYBOARD_INPUT ENDP
################
HANDLE_KEYBOARD_INPUT PROC NEAR
PUSH BX
LEA BX,KEYBOARD_TABLE
SPECIAL_LOOP:
CMP BYTE PTR [BX],0
JE END_HANDLE
CMP AL,[BX]
JE HANDLE_KEY
ADD BX,3
JMP SPECIAL_LOOP
HANDLE_KEY:
INC BX
CALL WORD PTR [BX]
END_HANDLE:
POP BX
RET
HANDLE_KEYBOARD_INPUT ENDP
All we need extra is:
KEYBOARD_TABLE LABEL BYTE
DB 72
DW OFFSET CGROUP:GO_TO_FUNCTION_ARROW_UP
DB 75
DW OFFSET CGROUP:GO_TO_FUNCTION_ARROW_LEFT
DB 77
DW OFFSET CGROUP:GO_TO_FUNCTION_ARROW_RIGHT
DB 80
DW OFFSET CGROUP:GO_TO_FUNCTION_ARROW_DOWN
DB 0
And a CALL CHECK_KEYBOARD_INPUT to check. May help.
Note: HANDLE_KEYBOARD_INPUT gives the scancode in AL to the function. So we can just use one sub for all 4 arrow keys (just compare AL with 72/75/77/80).
Greetz,
keinplan
Also, you may try to hook the int 09h. Every time an event occurs on the keyboard, the x86 stops and loads an adress of a code and runs it, then returns back
to her job. This is called inturrpt and the keyboards interrupt is 09h. At the segment 0000h the interrupt vector table exists. And all you'll do is find and
save the original interrupt's code's adress and replace it our new code's adress...
Remember that, when an interrupt occurs, the x86 can be anywhere, DS is also unpredictable. So CS is usefull and could be used for data storage like DS. Also
never forget to reset the int 09h while exiting your program.
We're going to make a buffer as a 128 bytes long. There are 127 keys and 127 scan codes. After that we are going to save the original int 09h vector and
replace it our code's vector. Our code's vector as SEGMENT:OFFSET is, CS:IP.
Our tiny code is going to check the port 60h and then clear the kb buffer. Then continue with the original int 09h. Continuing with original int 09h has some
benefits like detecting if 'right control key' is pressed or 'left control key' is pressed.
Also you must know the keyscan codes. It is easy to detect.
So, here we go!
.Data
KeyBuffer 128 dup(0)
.Code
add [bx + si], al ;we are going to write here the actual DS value
add [bx + si], al ;we are going to write here the offset of array keybuffer.
add [bx + si], al ;Offset Int 9h
add [bx + si], al ;Segment Int 9h
;installation
call init_new_int_09h
;your code here
;
;call LeftShift
;cmp al, 1
;je LeftShiftPressed
;
;mov al, 17
;call Key
;cmp al, 1
;je W_keyPressed
;
;
;e.t.c.
;
;
;after you're done
call Unhook_int_09h
;Terminate
init_new_int_09h Proc Near ;Tolga Arçok 2008 - 2010
mov si, 24h ;int 9h code adress. 0000:0024h
xor ax, ax ;9 * 4 = 36 = 24h. AX = 0.
push ds ;Save our ds.
mov ds, ax ;DS:SI = 0000:0024 we're ready to read the original int 09h code adress
mov es, ax ;ES = 0. and we're ready to write our new code's adres.
lodsw ;read a word 0000:0024
mov cx, ax ;CX = AX
lodsw ;Read one more word
pop ds ;Load back our DS
mov cs:0004h, cx ;I've allocated some bytes at the start of the code.
mov cs:0006h, ax ;Please notice that I'm not writing to DS.
;Since this is an interrupt, we may never know when it occurs.
;So we can not say we will be in our DS every time the interrupt occurs.
;That's why I allocated some bytes at the start of the code.
;We can always reach the CodeSegment. (64k limit!)
mov di, 24h ;ES:DI = 0000:0024 ready to write our new key handler's code adress
cli ;Interrupts cancelled
mov ax, offset new_int ;OFFSET of our key handler's code
stosw ;write to 0000:0024
mov ax, cs ;write our code's segment (CS) to 0000:0024
stosw ;
sti ;Enable the Interrupts
push cs ;Again we are going to write to CS
pop es ;ES = CS
xor di, di ;di = 0. The start of CS. First IP. CS:IP
mov ax, ds ;AX = DS
stosw ;Now DS's actual Value is in the CS:0000h
mov ax, offset Keybuffer ;KeyBuffer is an array of 128 bytes, declared at the segment Data.
stosw ;Now our key buffer's actual segment is at CS:0000h and offset is at CS:0002h
ret ;So we may always reach our keybuffer to read or write data
init_new_int_09h EndP ;Tolga Arçok 2008 - 2010
new_int: ;Tolga Arçok 2008 - 2010
pushf ;save flags
push ax ;and
push es ;the
push di ;registers
push ds ;we are
push si ;going to use
push cs ;CS
pop ds ;DS = CS
xor si, si ;DS:SI = CS:0000h
lodsw ;Read actual DS
mov es, ax ;ES = OUR DS
lodsw ;Read offset of keybuffer
mov di, ax ;ES:DI = DS:Keybuffer (No matter when the interrupt occured.)
xor ah, ah ;ah = 0
in al, 60h ;Read kb port. Something about the kb happened and we are here.
cmp al, 7Fh ;Port 60h has something to tell us. The message is in al.
ja keyreleased ;if al > 127 then the key is released.(Not pressed)
add di, ax ;Else the key is pressed and al is the key's scancode.
;ES:DI was DS:keybuffer. Now we move on the involved key's byte in keybuffer.
mov al, 1 ;AL = 1
stosb ;Now the key, which is pressed is signed as '1' in DS:keyboardbuffer + keyscancode
@1: ;We're Done
mov ax, 40h ;Clean up the mess...
mov es, ax ;Def Seg = &H40 : Poke 26, 30 : Poke 28, 30: Clears kb buffer
mov di, 26 ;Kb read quee reset
mov ax, 30 ;Kb read quee reset
stosb ;Kb read quee reset
inc di ;Kb read quee reset
stosb ;Kb read quee reset
pop si ;Get
pop ds ;back
pop di ;our own.
pop es ;
pop ax ;
popf ;Now jump to the original int 09h. (This way we can catch the alpha keys.)
jmp dword ptr cs:0004h ;For eample right control key, AltGr key etc...
Keyreleased: ;While ES:DI is DS:Keybuffer
and ax, 07Fh ;Clear the key released bit. What is left is the released key's scancode.
add di, ax ;Now ES:DI is DS:keyboardbuffer + released key's scancode.
xor ax, ax ;al = 0
stosb ;Clear there.
new_int ;We're done.
Key Proc Near ;Tolga Arçok 2008 - 2010
;Gets the keystate of given keys scancode in AL
;and returns in AL
push si ;if the key is pressed AL = 1 else AL = 0
mov si, offset keyboardbuffer
xor ah, ah
add si, ax
lodsb
pop si
ret
Key EndP
;The routinnes below returns AX = 1 if the requested alpha key is pressed else AX = 0
LeftCtrl Proc Near ;Tolga Arçok 2008 - 2010
push ds
xor ax, ax
mov ds, ax
mov si, 417h
lodsw
test ah, 1
jz Solctrl1
test al, 4
jz Solctrl1
mov ax, 1
SolCtrlTamam:
pop ds
ret
SolCtrl1:
xor ax, ax
jmp SolCtrlTamam
LeftCtrl EndP
RightCtrl Proc Far ;Tolga Arçok 2008 - 2010
push ds
xor ax, ax
mov ds, ax
mov si, 417h
lodsw
test ah, 1
jnz Sagctrl1
test al, 4
jz Sagctrl1
mov ax, 1
SagCtrlTamam:
pop ds
ret
SagCtrl1:
xor ax, ax
jmp SagCtrlTamam
RightCtrl EndP
RightShift Proc Near ;Tolga Arçok 2008 - 2010
push ds
xor ax, ax
mov ds, ax
mov si, 417h
lodsb
test al, 1
jz SagUstTus1
mov ax, 1
SagUstTusTamam:
pop ds
ret
SagUstTus1:
xor ax, ax
jmp SagUstTusTamam
RightShift Endp
LeftShift Proc Far ;Tolga Arçok 2008 - 2010
push ds
xor ax, ax
mov ds, ax
mov si, 417h
lodsb
test al, 2
jz SolUstTus1
mov ax, 1
SolUstTusTamam:
pop ds
ret
SolUstTus1:
xor ax, ax
jmp SolUstTusTamam
LeftShift EndP
AltKey Proc Near ;Tolga Arçok 2008 - 2010
push ds
xor ax, ax
mov ds, ax
mov si, 417h
lodsw
test ah, 2
jz AltTusu1
test al, 8
jz AltTusu1
mov ax, 1
AltTusuTamam:
pop ds
ret
AltTusu1:
xor ax, ax
jmp AltTusuTamam
AltKey EndP
AltGrKey Proc Far ;Tolga Arçok 2008 - 2010
push ds
xor ax, ax
mov ds, ax
mov si, 417h
lodsw
cmp ah, 0
jnz AltGrTusu1
test al, 8
jz AltGrTusu1
mov ax, 1
AltGrTusuTamam:
pop ds
ret
AltGrTusu1:
xor ax, ax
jmp AltGrTusuTamam
AltGrKey EndP
Unhook_int_09h Proc Near ;Tolga Arçok 2008 - 2010
xor ax, ax ;AX = 0
mov es, ax ;ES = 0
mov di, 24h ;0000:0024h Adress of INT 09H vector
mov ax, cs:0004h ;UNHOOK INT 09H
cli ;CLearInterrupt FLAG(CLI)
stosw ;AX = CS:0004h = INT 09H Code's Segment
mov ax, cs:0006h ;AX = CS:0006h = INT 09H Code's Offset
stosw ;UNHOOKED
sti ;SeTInterrupt(STI)
mov ax, 40h ;Clear
mov es, ax ;the
mov di, 23 ;shift key
xor al, al ;status
stosb ;0040:0017h = 0
Unhook_int_09h EndP
END
hope this is usefull for anyone who codes under 16 bit system and deals with the keyboard. There may be other ways or shorter ways but believe me that the
shift key status and calling the original interrupt 09h code while it is hooked is really cool stuff here :)
This post became a small keyboard tutorial, didn't it? :P
P.S. I could made some tiny mistakes but I'm sure if there was an error, you could easily fix it.
P.S. You can easily write a code to learn the scan codes with this code.
welcome to the forum Keinplan and Adam :U
this is kind of an old thread :P
still good info, though
Old thread, but may help a other one in the future :lol