;----------------------------------------------------------------------------------; 鼠标, 键盘和显示设备的汇编语言操作;; 在DOS系统或者命令行中运行 (在 win 下双击即可运行); 运行时跟踪鼠标的移动位置,捕获鼠标和键盘的击键情况; (*)当按下 [ESC] 键时程序退出,其它键,蜂鸣; (*)按下鼠标右键恢复初始显示方式,并发声; (*)按下鼠标左键仅产生噪音; (*)按下键盘上的 F1-F10 切换到不同的显示方式 .; ; 编译器: [MASM] [ 欢迎到群里下载:28011342 ]; (c) by 江南孤峰 Time: 2007--10--3 version: 1.0; **************************************************************************; **** 没有复杂的汇编语法,适合初学者完赏, 目前尚不完善,更新中……; **************************************************************************;---------------------------------------------------------------------------------- .model small ;----------------------------------------------------------------------------------.datamsgWin 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 $-msgHlpEndwindowEdge 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 ; 当前显示方式索引值,初始值对应 begModemsgModePrompt 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,2411soundFreqSize 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(?) ;----------------------------------------------------------------------------------.codemain proc farstar: 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 againmouseMove: ; 鼠标移动 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 againmainOver: call HideMouse ; 隐藏鼠标 call LocateScroll ; 重定位光标,并根据需要将窗口下滚一行 lea dx,msgEnd ; 提示信息 call PrintStr call WaitHitKey ; 等待用户按键 mov ax,0003h ; 恢复至DOS默认的显示模式 int 10h mov ax,4c00h int 21hmain 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 ; 显示鼠标, 大部分模式下默认不能显示 retInitScreen 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 LocScrOverLocScroll: 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 LocateCursorLocScrOver: retLocateScroll 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,4CHKBEND:retCheckKeyBd endp ;---------------------------------------------------------; 设置光标位置,页号皆为 0, DH/DL 已经相应存了 行/列 [SAFE];---------------------------------------------------------LocateCursor proc near push bx push ax mov bh,00h mov ah,02h int 10h pop ax pop bx retLocateCursor 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 ; 输出按键码 retSwitchMode 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 CKHITRNOCHG: mov ax,0 ; 没有鼠标按键 jmp CKOVERCKMOV: mov ax,3 ; 鼠标移动,保存新位置 mov savPosX,cx mov savPosY,dx jmp CKOVERCKHITL: mov ax,1 ; 左击捕获 jmp CKOVERCKHITR: mov ax,2 ; 右击捕获CKOVER: retCheckMouse 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 retResetMode endp ;---------------------------------------------------------; 声音制作,单击鼠标;---------------------------------------------------------MakeSound proc near mov dx,0MkSAgain: 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 retMakeSound endp ;---------------------------------------------------------; 与CPU工作频率无关的延迟, 延迟时间 (cx*15.08 微秒) [BOOK:391];---------------------------------------------------------GenWait proc nearinGenWait: in al,61h and al,10h cmp al,ah je inGenWait mov ah,al loop inGenWait retGenWait 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 retGenMakeSound endp ;---------------------------------------------------------; 隐藏光标,该函数无效,不知道什么原因 ????;---------------------------------------------------------HideCursor proc near mov cx,0ffffh ; ch 第4位为1时光标被隐藏 mov ah,01h ; 设置光标类型 int 10h retHideCursor endp ;---------------------------------------------------------; 等待按键;---------------------------------------------------------WaitHitKey proc near mov ah,00h ; 等待按键 int 16h retWaitHitKey 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 SSMsgNextSSMsgOver: retShowProMsg 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 retShowFramWin 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 PrintStrShowScrMode endp ;---------------------------------------------------------; 设置光标位置,新位置在DX中,DH/DL=行/列, BH 页号;---------------------------------------------------------SetCursor proc near mov ah,02h int 10h retSetCursor 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 retPrintKeyCode 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 bhNextbhLowerCase: mov bh,27h ; 小写形式输出bhNext: rol ax,cl mov bl,al and bl,0fh add bl,30h cmp bl,3ah jb bhPrint add bl,07hbhPrint: mov dl,bl push ax mov ah,02h int 21h dec ch pop ax jnz bhNext pop ax ; 恢复寄存器 pop bx pop cx pop dx retBinToHex endp ;---------------------------------------------------------; 测试键盘按键是否是显示方式切换的 "热键" (F1-F10); 键码存于keyBdIn 中。 若是则 ax 置为 2;---------------------------------------------------------IsModeChange proc near mov bx,3a00h ; 初始化,3b00h 是 F1 mov ax,keyBdInIsHotF: inc bh cmp ax,bx jz IsHotKey ; 是 热键 F1-F10 cmp bx,4400h ; 4400h 是 F10 jz IsMCOver jmp IsHotFIsHotKey: mov ax,2IsMCOver: retIsModeChange endp ;---------------------------------------------------------; 屏幕打印字符,字符已经存入 dl 中;---------------------------------------------------------PrintChar proc near mov ah,02h int 21h retPrintChar endp ;---------------------------------------------------------; 屏幕打印字符串,字符串偏移地址已经存入 dx 中;---------------------------------------------------------PrintStr proc near mov ah,09h int 21h retPrintStr endp ;---------------------------------------------------------; 鼠标初始化;---------------------------------------------------------InitMouse proc near mov ax,0000h ; 鼠标复位 int 33h call InitPos ; 初始化鼠标位置 retInitMouse endp ;---------------------------------------------------------; 显示鼠标;---------------------------------------------------------ShowMouse proc near mov ax,0001h int 33h retShowMouse endp ;---------------------------------------------------------; 隐藏鼠标;---------------------------------------------------------HideMouse proc near mov ax,0002h int 33h retHideMouse endp ;---------------------------------------------------------; 初始化鼠标位置;---------------------------------------------------------InitPos proc near mov ax,0004h mov cx,42 ; 水平位置 mov dx,18 ; 垂直位置 int 33h retInitPos endp;---------------------------------------------------------------------------------- end star

评论