正文

鼠标键盘监控{汇编代码,初学者}2007-10-05 13:37:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lingdlz/29863.html

分享到:

;----------------------------------------------------------------------------------
; 鼠标, 键盘和显示设备的汇编语言操作
;
; 在DOS系统或者命令行中运行 (在 win 下双击即可运行)
; 运行时跟踪鼠标的移动位置,捕获鼠标和键盘的击键情况
; (*)当按下 [ESC] 键时程序退出,其它键,蜂鸣
; (*)按下鼠标右键恢复初始显示方式,并发声
; (*)按下鼠标左键仅产生噪音
; (*)按下键盘上的 F1-F10 切换到不同的显示方式 .
;
; 编译器: [MASM] [ 欢迎到群里下载:28011342 ]
; (c) by 江南孤峰   Time: 2007--10--3   version: 1.0
; **************************************************************************
; **** 没有复杂的汇编语法,适合初学者完赏, 目前尚不完善,更新中……
; **************************************************************************
;----------------------------------------------------------------------------------

.model small

;----------------------------------------------------------------------------------
.data
msgWin          db  'Mouse or Keyboard message show as follow: $'
msgHlpStar      db  ' ================= INFOMATION ==================$'
                db  '      * Press key [ESC] to exit                 $'
                db  '      * Hit right mouse key to normal mode      $'
                db  '      * Hit left mouse key to make sound        $'
                db  '      * Press key F1-F10 to change show mode    $'
                db  '  (c) by JiangNanGuFeng    Time: 2007 - 10 - 4  $'
                db  '  Email: lingdlz@163.com     QQ: 403324669      $'  
msgHlpEnd       db  ' ===============================================$'
msgLineLen      dw  $-msgHlpEnd
windowEdge      db  '**********************************************************$'

msgMouseMove    db  'Mouse message : mouse move new pos: $'
msgMouseLeft    db  'Mouse message : hit left key $'
msgMouseRight   db  'Mouse message : hit right key $'
msgKeyBd        db  'Keyboard message: hit key, code [$'
msgStart        db  'Press any key to start ......$'
msgEnd          db  'Press any key to exit ......$'

showMode        db  03h,04h,06h,09h,0dh,0eh,0fh,10h,11h,13h,'$'
begMode         dw  000fh       ; 最初的显示方式
currentMode     dw  6           ; 当前显示方式索引值,初始值对应 begMode
msgModePrompt   db  'Mode Info :$'
msgMode         db  'AL=03 WIDTH=80 HIGHT=25 COLOR=16 MODE=text      $'
                db  'AL=04 WIDTH=320 HIGHT=200 COLOR=4 MODE=graph    $'
                db  'AL=06 WIDTH=640 HIGHT=200 COLOR=w/b MODE=text   $'
                db  'AL=09 WIDTH=320 HIGHT=200 COLOR=16 MODE=graph\MC$'
                db  'AL=0d WIDTH=320 HIGHT=200 COLOR=16 MODE=graph\EV$'
                db  'AL=0e WIDTH=640 HIGHT=200 COLOR=16 MODE=graph\EV$'
                db  'AL=0f WIDTH=640 HIGHT=350 COLOR=sig MODE=text\EV$'
                db  'AL=10 WIDTH=640 HIGHT=350 COLOR=16 MODE=graph\EV$'
                db  'AL=11 WIDTH=640 HIGHT=480 COLOR=w/b MODE=text   $'
                db  'AL=13 WIDTH=320 HIGHT=200 COLOR=256 MODE=graph\E$'
;--------------------------------------------------------------------------------
; msgMode 说明:AL 设置该显示方式时的调用参数; WIDTH/HIGHT 表示屏幕像素或者
;               字符行列数; COLOR 表示颜色数, 其中w/b表示黑白,sig 单色;
;               MODE: text 表示文本模式, graph 图形模式, MC: MCGA,E: EGA, V: VGA
;--------------------------------------------------------------------------------

soundFreq       dw  31,61,122,144,419,817,840,911
                dw  62,144,446,799,819,1104,1715,2411
soundFreqSize   db  $-soundFreq ; 音符频率,键盘击键时发声

newLine         db  13,10,'$'
savStat         dw  0       ; 保存鼠标击键情况
savPosX         dw  22      ; 鼠标的X坐标, 22 是初始位置
savPosY         dw  62      ; 鼠标的Y坐标, 62 是初始位置
keyBdIn         dw  ?       ; 保存最新的键盘按键
isScroll        db  0       ; 窗口是否需要上滚,0 否,1 是
scroLine        db  ?       ; 窗口滚动时,卷入行的属性
countColumn     db  ?       ; 当前显示方式的字符列数
winTopRow       dw  0c08h   ; 窗口部分的最上边
winBottomRow    dw  1408h   ; 窗口部分的最下边,[04]最后会改为字符列数
rlt_asc         db  10 dup(?)
temp_asc        db  10 dup(?)

;----------------------------------------------------------------------------------
.code
main    proc    far
star:   mov ax,@data
    mov ds,ax
    mov ax,begMode          ; 初始化显示方式
    int 10h
    call    InitScreen      ; 初始化屏幕
    call    LocateScroll    ; 定位光标,或者滚动窗口
    Lea dx,msgStart         ; 第一条消息
    call    PrintStr
    call    WaitHitKey      ; 等待用户按键 

again:  call    CheckKeyBd  ; 检查鼠标消息,即是否有击键
    cmp ax,4                ; 击键[ESC],退出程序
    jz  mainOver
    cmp ax,2                ; 显示方式切换
    jnz testMouse
    call    SwitchMode      ; 切换显示方式
testMouse:
    call    CheckMouse      ; 检查鼠标状态,是否发生变化
    cmp al,0
    jz  again               ; 鼠标状态没有改变
    cmp al,3
    jz  mouseMove           ; 移动
    call    MakeSound       ; 单击了鼠标,发噪音
    cmp al,1                ; 鼠标情况
    jz  hitLef              ; 左击
    cmp al,2       
    jz  hitRig              ; 右击
   
hitLef: call    LocateScroll; 左击处理,这里可以调用某些函数
    lea dx,msgMouseLeft
    call    PrintStr
    jmp again

hitRig: call    ResetMode   ; 恢复至最初的显示状态
    jmp again
mouseMove:                  ; 鼠标移动
    call    LocateScroll
    lea dx,msgMouseMove
    call    PrintStr
    mov dl,'('
    call    PrintChar
    mov ax,savPosX          ; 水平位置
    call    BinToHex        ; 以十六进制形式打印出来
    mov dl,','
    call    PrintChar
    mov ax,savPosY          ; 垂直位置
    call    BinToHex
    mov dl,')'
    call    PrintChar
    jmp again
mainOver:  
    call    HideMouse       ; 隐藏鼠标
    call    LocateScroll    ; 重定位光标,并根据需要将窗口下滚一行 
    lea dx,msgEnd           ; 提示信息
    call    PrintStr
    call    WaitHitKey      ; 等待用户按键
    mov ax,0003h            ; 恢复至DOS默认的显示模式
    int 10h
    mov ax,4c00h
    int 21h
main    endp

;---------------------------------------------------------
; 初始化屏幕
;---------------------------------------------------------
InitScreen  proc    near
    call    HideCursor      ; 隐藏光标  [无效] ??
    call    ShowProMsg      ; 打印程序的有关信息
    call    ShowFramWin     ; 打印屏幕小窗口
    call    ShowScrMode     ; 打印当前显示方式的有关信息
    mov ah,08h              ; 读光标位置的字符和属性
    mov bh,00h
    int 10h    
    mov scroLine,al         ; 保存字符属性,作为窗卷入行属性
    mov ah,0fh              ; 取当前显示方式
    int 10h
    cmp al,03h
    jnz NotNormalDos        ; 测试是否是DOS默认的显示模式
    mov al,07h              ; 普通卷入行属性 DOS
    mov scroLine,al         ; 卷入行属性
NotNormalDos:
    mov countColumn,ah      ; 保存字符列数
    mov dx,winTopRow        ; winTopRow 是标题所在行
    inc dh
    call    LocateCursor    ; 光标定位到窗口上边缘
    mov al,0
    mov isScroll,al         ; 恢复滚动标记
    call    InitMouse       ; 初始化鼠标
    call    ShowMouse       ; 显示鼠标, 大部分模式下默认不能显示
    ret
InitScreen  endp

;---------------------------------------------------------
; 重定位光标,并根据需要将窗口下滚一行
;---------------------------------------------------------
LocateScroll    proc    near
    cmp isScroll,1          ; 滚动标记已经设置
    jz  LocScroll  
    mov ah,03h              ; 读当前光标位置       
    mov bh,00h              ; 页号,0
    int 10h
    mov cx,winBottomRow
    dec ch                  ; 修正
    cmp dh,ch               ; 是否到达窗口底部
    jb  LocAddRow           ; 增加行号
    mov al,1
    mov isScroll,1 
    jmp LocScroll           ; 下滚一行
LocAddRow:
    mov cx,winTopRow
    add cl,4                ; 修正,也就是缩进 4 格
    mov dl,cl
    inc dh                  ; 行号增 1
    call    LocateCursor
    jmp LocScrOver
LocScroll:
    mov ax,0701h            ; ah 功能号,al 滚动行数
    mov bh,scroLine         ; 卷入行属性,普通
    mov cx,winTopRow        ; 窗口左上角
    add ch,2                ; 内容滚动区修正
    mov dx,winBottomRow     ; 窗口右下角
    dec dh                  ; 修正
    mov dl,countColumn      ; 字符列数
    int 10h
    mov dx,winTopRow        ; 重定位光标到窗口顶部
    add dh,2
    add dl,4
    call    LocateCursor
LocScrOver:
    ret
LocateScroll    endp


;---------------------------------------------------------
; 检查是否有键盘击键情况,若有,则输出对应键的字符码和扫
; 描码, 若所击键为 [ESC],则 ax 设置为 4, 如果是显示方式
; 切换热键,则 ax 设置为 2
;---------------------------------------------------------
CheckKeyBd  proc    near
    mov ah,01h
    int 16h                 ; 取键盘缓冲区状态
    jz  CHKBEND             ; 键盘无按键
    mov keyBdIn,ax          ; 保存 ax 中的内容

    push    ax
    mov al,ah               ; 按键发声,扫描码取模后作为索引
    xor ah,ah
    div soundFreqSize
    xor bh,bh
    mov bl,ah               ; 取扫描码除soundFreqSize 后的余数
    mov di,soundFreq[bx]
    mov cx,0afffh   ; 延迟
    call    GenMakeSound   
    pop ax

    call    IsModeChange    ; 测试是否是显示方式切换的 "热键"
    cmp ax,2
    jz  CHKBEND             ; 是显示方式切换 "热键"
    call    LocateScroll    ; 重定位光标,并根据需要将窗口下滚一行
    call    PrintKeyCode    ; 以十六进制形式输出键盘码
    mov ax,keyBdIn          ; 测试是否是 [ESC] 键
    cmp ax,011bh            ; 011bh 是ESC的按键码
    jnz CHKBEND
    mov ax,4
CHKBEND:ret
CheckKeyBd  endp

;---------------------------------------------------------
; 设置光标位置,页号皆为 0, DH/DL 已经相应存了 行/列 [SAFE]
;---------------------------------------------------------
LocateCursor    proc    near
    push    bx
    push    ax
    mov bh,00h
    mov ah,02h
    int 10h
    pop ax
    pop bx
    ret
LocateCursor    endp

;---------------------------------------------------------
; 切换显示方式, 切换之后,重新运行所有初始化操作
;---------------------------------------------------------
SwitchMode  proc    near
    mov bx,keyBdIn
    sub bx,3b00h            ; 3b00h 是F1的按键码
    mov bl,bh
    mov bh,0                ; 清0,使 bx 成为索引
    mov al,byte ptr showMode[bx]
    mov ah,00h
    int 10h
    mov currentMode,bx      ; 设置索引
    call    InitScreen
    call    LocateScroll    ; 光标处理,窗口下滚
    call    PrintKeyCode    ; 输出按键码
    ret
SwitchMode  endp

;---------------------------------------------------------
; 检查鼠标状态,是否发生变化( 移动,或者击键 )
; 如果是击键则 ax 置为 1(左击)或者 2(右击)
; 如果是移动则将新位置存入 savPosX,savPosY, ax 置为 3
; 如果鼠标状态没有发生变化 ax 置为 0
;---------------------------------------------------------
CheckMouse  proc    near
    mov ax,0003h            ; 读取鼠标状态
    int 33h
    cmp cx,savPosX          ; 是否移动了鼠标
    jnz CKMOV
    cmp dx,savPosY
    jnz CKMOV
    cmp bx,savStat          ; 测试是否有鼠标按键
    jz  NOCHG               ; 没有鼠标按键
    mov savStat,bx
    cmp bx,1                ; 左击
    jz  CKHITL
    cmp bx,2                ; 右击
    jz  CKHITR
NOCHG:  mov ax,0            ; 没有鼠标按键
    jmp CKOVER
CKMOV:  mov ax,3            ; 鼠标移动,保存新位置
    mov savPosX,cx
    mov savPosY,dx
    jmp CKOVER
CKHITL: mov ax,1            ; 左击捕获
    jmp CKOVER
CKHITR: mov ax,2            ; 右击捕获
CKOVER: ret
CheckMouse  endp

;---------------------------------------------------------
; 设为DOS普通的显示模式
;---------------------------------------------------------
ResetMode   proc    near
    mov al,03h              ; DOS下的普通模式
    mov ah,00h              ; 恢复开始的显示方式
    int 10h
    mov ax,0
    mov currentMode,ax      ; 当前显示方式索引
    call    InitScreen
    call    LocateScroll   
    lea dx,msgMouseRight
    call    PrintStr
    ret
ResetMode   endp

 

;---------------------------------------------------------
; 声音制作,单击鼠标
;---------------------------------------------------------
MakeSound   proc    near
    mov dx,0
MkSAgain:
    mov bx,0   
MkSNext:
    mov di,soundFreq[bx]
    mov cx,04fh
    call    GenMakeSound
    inc bl
    cmp bl,soundFreqSize
    jb  MkSNext
    inc dx
    cmp dx,0fh
    jnz MkSAgain
    ret
MakeSound   endp

;---------------------------------------------------------
; 与CPU工作频率无关的延迟, 延迟时间 (cx*15.08 微秒) [BOOK:391]
;---------------------------------------------------------
GenWait     proc    near
inGenWait:
    in  al,61h
    and al,10h
    cmp al,ah
    je  inGenWait
    mov ah,al
    loop    inGenWait
    ret
GenWait     endp

;---------------------------------------------------------
; 利用8253/8254/8255产生指定频率声音的通用发声程序
; 指定频率 Di (19-65535Hz) [BOOK:Pg389]
;  CX 持续时间 (cx*15.08 微秒) [BOOK:391]   [SAFE]
;---------------------------------------------------------
GenMakeSound    proc    near
    push    dx
    push    di
    push    ax
    mov al,0b6h             ; 初始化8253/8254的计数器2
    out 43h,al
    mov dx,12h 
    mov ax,348ch
    div di                  ; 根据频率计算计数值 42h
    out 42h,al
    mov al,ah
    out 42h,al              ; 计数值送端口 42h,以建立声音频率
    in  al,61h              ; 61h为8255(a)输出端口
    mov ah,al               ; 保存当前值
    or  al,03h     
    out 61h,al              ; 打开声音开关
    call    GenWait         ; 与CPU工作频率无关的延迟
    mov al,ah               ; 恢复 61h 端口状态
    out 61h,al
    pop ax
    pop di
    pop dx
    ret
GenMakeSound    endp

;---------------------------------------------------------
; 隐藏光标,该函数无效,不知道什么原因 ????
;---------------------------------------------------------
HideCursor  proc    near
    mov cx,0ffffh           ; ch 第4位为1时光标被隐藏
    mov ah,01h              ; 设置光标类型
    int 10h
    ret
HideCursor  endp

;---------------------------------------------------------
; 等待按键
;---------------------------------------------------------
WaitHitKey  proc    near
    mov ah,00h              ; 等待按键
    int 16h
    ret
WaitHitKey  endp

;---------------------------------------------------------
; 在屏幕特定位置显示帮助信息
;---------------------------------------------------------
ShowProMsg  proc    near
    lea si,msgHlpEnd
    mov bx,0
    mov cx,010ah            ; 用于设置光标位置CH/CL , 行/列
SSMsgNext:
    inc ch                  ; 重设光标位置,行号增一
    mov dx,cx
    call    LocateCursor
    lea dx,msgHlpStar[bx]
    call    PrintStr
    cmp dx,si
    jnb SSMsgOver
    add bx,msgLineLen
    jmp SSMsgNext
SSMsgOver:
    ret
ShowProMsg  endp

;---------------------------------------------------------
; 打印屏幕上小窗口的框架
;---------------------------------------------------------
ShowFramWin proc    near
    mov dx,winTopRow        ; 窗口标题文字
    call    LocateCursor
    lea dx,msgWin
    call    PrintStr
    mov dx,winTopRow   
    inc dh                  ; 窗口顶部边界
    call    LocateCursor
    lea dx,windowEdge
    call    PrintStr
    mov dx,winBottomRow     ; 窗口底部边界
    call    LocateCursor
    lea dx,windowEdge
    call    PrintStr
    ret
ShowFramWin endp

;---------------------------------------------------------
; 在屏幕小窗口的下部,打印当前显示模式信息
;---------------------------------------------------------
ShowScrMode proc    near
    mov dx,winBottomRow
    add dh,2
    add dl,2
    call    LocateCursor    ; 重设光标位置
    lea dx,msgModePrompt
    call    PrintStr
    mov ax,currentMode
    mul msgLineLen
    mov bx,ax
    lea dx,msgMode[bx]
    call    PrintStr
ShowScrMode endp

;---------------------------------------------------------
; 设置光标位置,新位置在DX中,DH/DL=行/列, BH 页号
;---------------------------------------------------------
SetCursor   proc    near
    mov ah,02h
    int 10h
    ret
SetCursor   endp   

;---------------------------------------------------------
; 打印键盘的击键信息(按键码)其中存于 keyBdIn 变量中
;---------------------------------------------------------
PrintKeyCode    proc    near
    lea dx,msgKeyBd         ; 打印十六进制的按键码
    call    PrintStr
    mov ax,keyBdIn
    call    BinToHex        ; 转为十六进制ASCLL码形式输出到屏幕
    mov dl,']'              ; 分割符
    call    PrintChar
    mov dl,' '
    call    PrintChar
    mov ah,0ch              ; 调用DOS中断,清空键盘缓冲区
    int 21h
    mov dx,keyBdIn          ; 打印字符
    call    PrintChar
    ret
PrintKeyCode    endp

;---------------------------------------------------------
; 将 ax 中的二进制转为 十六进制 ASCALL 码输出到屏幕
; 如果需要以小写形式输出则将 bx 设置为 4    [SAFE]
;---------------------------------------------------------
BinToHex    proc    near
    push    dx              ; 保存寄存器
    push    cx
    push    bx
    push    ax
    mov cx,0404h            ; ch 控制循环次数,cl控制移位数
    cmp bx,4
    jz  bhLowerCase
    mov bh,07h              ; 大写形式输出 
    jmp bhNext
bhLowerCase:
    mov bh,27h              ; 小写形式输出
bhNext: rol ax,cl
    mov bl,al
    and bl,0fh
    add bl,30h
    cmp bl,3ah
    jb  bhPrint
    add bl,07h
bhPrint:
    mov dl,bl
    push    ax
    mov ah,02h
    int 21h
    dec ch
    pop ax
    jnz bhNext 
    pop ax                  ; 恢复寄存器
    pop bx
    pop cx
    pop dx 
    ret
BinToHex    endp

;---------------------------------------------------------
; 测试键盘按键是否是显示方式切换的 "热键" (F1-F10)
; 键码存于keyBdIn 中。 若是则 ax 置为 2
;---------------------------------------------------------
IsModeChange    proc    near
    mov bx,3a00h            ; 初始化,3b00h 是 F1
    mov ax,keyBdIn
IsHotF: inc bh
    cmp ax,bx
    jz  IsHotKey            ; 是 热键 F1-F10
    cmp bx,4400h            ; 4400h 是 F10
    jz  IsMCOver
    jmp IsHotF
IsHotKey:
    mov ax,2
IsMCOver:
    ret
IsModeChange    endp


;---------------------------------------------------------
; 屏幕打印字符,字符已经存入 dl 中
;---------------------------------------------------------
PrintChar   proc    near
    mov ah,02h
    int 21h
    ret
PrintChar   endp

;---------------------------------------------------------
; 屏幕打印字符串,字符串偏移地址已经存入 dx 中
;---------------------------------------------------------
PrintStr    proc    near
    mov ah,09h
    int 21h
    ret
PrintStr    endp

;---------------------------------------------------------
; 鼠标初始化
;---------------------------------------------------------
InitMouse   proc    near
    mov ax,0000h            ; 鼠标复位
    int 33h
    call    InitPos         ; 初始化鼠标位置
    ret
InitMouse   endp

;---------------------------------------------------------
; 显示鼠标
;---------------------------------------------------------
ShowMouse   proc    near
    mov ax,0001h
    int 33h
    ret
ShowMouse   endp

;---------------------------------------------------------
; 隐藏鼠标
;---------------------------------------------------------
HideMouse   proc    near
    mov ax,0002h
    int 33h
    ret
HideMouse   endp

;---------------------------------------------------------
; 初始化鼠标位置
;---------------------------------------------------------
InitPos     proc    near
    mov ax,0004h
    mov cx,42               ; 水平位置
    mov dx,18               ; 垂直位置
    int 33h
    ret
InitPos     endp
;----------------------------------------------------------------------------------
        end star

 

阅读(6916) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册