TASM中的虚拟键盘

时间:2019-04-25 20:18:29

标签: assembly x86-16 tasm dosbox

我知道这是一个漫长的过程,但是我被困在一个学校组装项目的中间,而且由于我对编程还很陌生,所以我很难在我的问题中查找问题代码。

我正在尝试制作虚拟(屏幕上的)键盘。每个按钮的位置值有2个数组,一个为按钮中心的X值,另一个为Y。

示例数组键盘的第一行:

x_arr dw 13,37,61,85,109,133,157,181,205,229
y_arr dw 113,113,113,113,113,113,113,113,113,113

计算机等待用户的鼠标单击,然后使用算法查找是否按下了按钮或按下了哪个按钮,然后将该按钮与每个字母的ascii值数组进行匹配:

letter_arr db 81,87,68,82,84,89,85,73,79,80 ;QWERTYUIOP

我的程序似乎不起作用。我将添加完整的代码和键盘本身的图片。

对不起,如果有什么麻烦的话。预先感谢!

image link

IDEAL
MODEL small
STACK 0f500h
;---------------
MAX_BMP_WIDTH = 320
MAX_BMP_HEIGHT = 200
SMALL_BMP_HEIGHT = 40
SMALL_BMP_WIDTH = 40

DATASEG

    ;------Image related data------
    OneBmpLine db MAX_BMP_WIDTH dup (0)  ;One Color line read buffer
    ScreenLineMax db MAX_BMP_WIDTH dup (0)  ;One Color line read buffer
    FileHandle dw ?
    Header db 54 dup(0)
    Palette db 400h dup (0)
    SmallPicName db 'keyboar1.bmp',0
    BmpFileErrorMsg db 'Error At Opening Bmp File .', 0dh, 0ah,'$'
    ErrorFile db 0
    BB db "BB..",'$'     
    BmpLeft dw ?
    BmpTop dw ?
    BmpColSize dw ?
    BmpRowSize dw ?
    ;-----Program related data-----
    mouse_click dw ?
    letter_arr db 81,87,68,82,84,89,85,73,79,80         ;array containing ascii values of letters
    x_arr dw 13,37,61,85,109,133,157,181,205,229        ;array containing x value of center of buttons representing letters in letter_arr
    y_arr dw 113,113,113,113,113,113,113,113,113,113    ;array containing y value of center of buttons representing letters in letter_arr
    mouse_last_button dw 0  ;holds the value of last mouse button clicked
    mouse_button dw 1       ;holds the value of mouse button clicked

CODESEG

;================PROCEDURES================
;-----------------
proc OpenShowBmp near
    push cx
    push bx
    call OpenBmpFile
    cmp [ErrorFile],1
    je @@ExitProc
    call ReadBmpHeader
    ; from  here assume bx is global param with file handle. 
    call ReadBmpPalette
    call CopyBmpPalette
    call ShowBMP 
    call CloseBmpFile
@@ExitProc:
    pop bx
    pop cx
    ret
endp OpenShowBmp    
;-----------------
proc OpenBmpFile    near                         
;input dx filename to open  
    mov ah, 3Dh
    xor al, al
    int 21h
    jc @@ErrorAtOpen
    mov [FileHandle], ax
    jmp @@ExitProc  
@@ErrorAtOpen:
    mov [ErrorFile],1
@@ExitProc: 
    ret
endp OpenBmpFile

proc CloseBmpFile near
    mov ah,3Eh
    mov bx, [FileHandle]
    int 21h
    ret
endp CloseBmpFile
;-----------------
proc ReadBmpHeader  near                    
; Read 54 bytes the Header  
    push cx
    push dx

    mov ah,3fh
    mov bx, [FileHandle]
    mov cx,54
    mov dx,offset Header
    int 21h

    pop dx
    pop cx
    ret
endp ReadBmpHeader
;-----------------
proc ReadBmpPalette near
; Read BMP file color palette, 256 colors * 4 bytes (400h)
; 4 bytes for each color BGR + null)            
    push cx
    push dx

    mov ah,3fh
    mov cx,400h
    mov dx,offset Palette
    int 21h

    pop dx
    pop cx

    ret
endp ReadBmpPalette
;-----------------
proc CopyBmpPalette near                    
; Will move out to screen memory the colors
; video ports are 3C8h for number of first color
; and 3C9h for all rest                                 
    push cx
    push dx

    mov si,offset Palette
    mov cx,256
    mov dx,3C8h
    mov al,0  ; black first                         
    out dx,al ;3C8h
    inc dx    ;3C9h
CopyNextColor:
    mov al,[si+2]       ; Red               
    shr al,2            ; divide by 4 Max (cos max is 63 and we have here max 255 ) (loosing color resolution).             
    out dx,al                       
    mov al,[si+1]       ; Green.                
    shr al,2            
    out dx,al                           
    mov al,[si]         ; Blue.             
    shr al,2            
    out dx,al                           
    add si,4            ; Point to next color.  (4 bytes for each color BGR + null)             

    loop CopyNextColor

    pop dx
    pop cx

    ret
endp CopyBmpPalette
;-----------------
proc ShowBMP 
; BMP graphics are saved upside-down.
; Read the graphic line by line (BmpRowSize lines in VGA format),
; displaying the lines from bottom to top.
    push cx

    mov ax, 0A000h
    mov es, ax

    mov cx,[BmpRowSize]

    mov ax,[BmpColSize] ; row size must dived by 4 so if it less we must calculate the extra padding bytes
    xor dx,dx
    mov si,4
    div si
    mov bp,dx

    mov dx,[BmpLeft]

@@NextLine:
    push cx
    push dx

    mov di,cx  ; Current Row at the small bmp (each time -1)
    add di,[BmpTop] ; add the Y on entire screen

    ; next 5 lines  di will be  = cx*320 + dx , point to the correct screen line
    mov cx,di
    shl cx,6
    shl di,8
    add di,cx
    add di,dx

    ; small Read one line
    mov ah,3fh
    mov cx,[BmpColSize]  
    add cx,bp  ; extra  bytes to each row must be divided by 4
    mov dx,offset ScreenLineMax
    int 21h
    ; Copy one line into video memory
    cld ; Clear direction flag, for movsb
    mov cx,[BmpColSize]  
    mov si,offset ScreenLineMax
    rep movsb ; Copy line to the screen

    pop dx
    pop cx

    loop @@NextLine

    pop cx
    ret
endp ShowBMP
;-----------------
proc setGraphic
    ;sets graphic mode
    mov ax, 13h
    int 10h
    ret
endp setGraphic
;-----------------
proc initMouse
    ;initializes mouse
    mov ax, 0
    int 33h ;resets mouse

    mov ax, 1
    int 33h ;shows pointer
    ret
endp initMouse
;-----------------
proc initImage
    ;imports keyboard bitmap
    mov [BmpLeft],0
    mov [BmpTop],0
    mov [BmpColSize], 320
    mov [BmpRowSize] ,200
    mov dx,offset SmallPicName
    call OpenShowBmp
    ret
endp initImage
;-----------------
proc getMouseClick
    mov ax, [mouse_button] ;stores te value of the last state of the mouse
    mov [mouse_last_button], ax

    mov ax, 03h
    int 33h ;gets mouse information

    mov [mouse_button], bx ;saves the click inforamtion
    shr cx, 1 ;halves the x position value since the interrupt returns double
    ret
endp getMouseClick
;-----------------
proc checkMouseButton
    mov ax, [mouse_button]      ;waits for the user to click left mouse button
    cmp ax, 1
    jne mouseLoop

    cmp ax, [mouse_last_button] ;if button pressed before is the same as the current one,
    jne mouseLoop               ;skip the letter printing
    jmp doLoop
    ret
endp checkMouseButton
;-----------------
proc checkX 
    mov ax,cx   ;saves the x value of the click for later
    pop cx  ;pops the current value of counter to cx
    push ax
    mov si, offset x_arr
    add si,cx
    mov ax, [si]    ;moves the value at x array at index number cx (counter) to ax

    ;add ax, 9  ;checks if the click was inside a button range on x axis (9 pixels left and right of the center)
    pop cx
    cmp cx, ax
    ja mouseLoop

    mov ax, [si]
    sub ax, 9
    cmp cx, ax
    jb mouseLoop
endp checkX
;-----------------
proc checkY
    mov si, offset y_arr
    add si,cx
    mov ax, [si]

    sub ax, 9   ;checks if the click was inside a button range on y axis (9 pixels above and below the center)
    cmp dx, ax
    jb mouseLoop

    mov ax, [si]
    add ax, 9
    cmp dx, ax
    ja writeLetter
    ret
endp checkY
;-----------------
proc printLetter
    mov si, offset letter_arr   ;prints the letter whose ascii value matches the x and y values found previously
    add si,cx
    mov dl, [si]
    mov ah, 2h
    int 21h
    ret
endp printLetter
;-----------------
;================PROCEDURES================

start:
    mov ax,@data
    mov ds,ax

    call setGraphic ;sets graphic mode
    call initMouse ;initializes mouse
    call initImage  ;displays keyboard image

    mov cx, 10 ;iterates over all of the buttons in the keyboard until one matches a clicks location
mouseLoop:
    push cx
    call getMouseClick
    call checkMouseButton
    call checkX
    call checkY
    pop cx
    dec cx
    loop mouseLoop

writeLetter:
    call printLetter

doLoop: 
    mov cx,10 
    jmp mouseLoop

exit:
    mov ax, 4c00h
    int 21h
END start

1 个答案:

答案 0 :(得分:1)

 mov cx, 10 ;iterates over all of the buttons in the keyboard until one matches a clicks location
mouseLoop:
 push cx
 call getMouseClick
 call checkMouseButton
 call checkX
 call checkY
 pop cx
 dec cx
 loop mouseLoop
writeLetter:
 call printLetter
doLoop: 
 mov cx,10 
 jmp mouseLoop

这是您的主程序循环。因为它们是过程,所以人们期望 getMouseClick checkMouseButton checkX checkY 返回{ {1}}。

只有 getMouseClick 像下降程序一样!

但是:

a。 checkMouseButton 跳回到 mouseLoop doLoop
 b。 checkX 跳回到 mouseLoop ,甚至认为它弹出call,而实际上它正在弹出返回地址!
 C。 checkY 跳回到 mouseLopp writeLetter

这些回调均不会删除返回地址和将CX压入堆栈

您需要完全重新考虑这一点...


CX

您知道dec cx loop mouseLoop 已经减少了loop寄存器。为什么要另外使用CX指令?