News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Waiting for the arrow key

Started by amrac, December 28, 2009, 11:20:16 PM

Previous topic - Next topic

amrac

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?

dedndave

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


FORTRANS

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.

dedndave

in his other thread, i gave him a nice little proc to do that   :bg

keinplan

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

SayisalAdam

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.

dedndave

welcome to the forum Keinplan and Adam   :U

this is kind of an old thread   :P

still good info, though

keinplan

Old thread, but may help a other one in the future  :lol