BIOS 级编程与鼠标编程详解
1. 像素绘制与颜色设置
在视频模式 13h 下,我们可以进行像素绘制和颜色设置。以下是一个示例代码,用于将调色板索引 1 的颜色设置为白色(RGB 值为 63,63,63),并在屏幕中间绘制 10 个像素:
; Sets individual palette colors and draws
; several pixels.
;------------------------------------------------
; Change the color at index 1 to white (63,63,63).
mov dx,VIDEO_PALLETE_PORT
mov al,1
; set palette index 1
out dx,al
mov dx,COLOR_SELECTION_PORT
mov al,63
; red
out dx,al
mov al,63
; green
out dx,al
mov al,63
; blue
out dx,al
; Calculate the video buffer offset of the first pixel.
; Method is specific to mode 13h, which is 320 X 200.
mov xVal,160
; middle of screen
mov yVal,100
mov ax,320
; 320 for video mode 13h
mul yVal
; y-coordinate
add ax,xVAl
; x-coordinate
; Place the color index into the video buffer.
mov cx,10
; draw 10 pixels
mov di,ax
; AX contains buffer offset
; Draw the pixels now. By default, the assembler assumes
; DI is an offset from the segment address in DS. The
; segment override ES:[DI] tells the CPU to use the segment
; address in ES instead. ES currently points to VRAM.
DP1:
mov BYTE PTR es:[di],COLOR_INDEX
add di,5
; move 5 pixels to the right
loop DP1
ret
Draw_Some_Pixels ENDP
END main
这个程序相对容易实现,因为像素都在同一屏幕行上。如果要绘制垂直线,可以每次将 DI 的值增加 320 以移动到下一行像素;绘制斜率为 1 的对角线,则可以将 DI 增加 321。对于任意两点之间的直线绘制,Bresenham 算法是最佳选择,该算法在许多网站上都有详细解释。
2. 视频模式 13h 相关问题解答
以下是一些关于视频模式 13h 的常见问题及解答:
|问题|答案|
|----|----|
|(True/False): Video mode 13h maps screen pixels as a two-dimensional array of bytes, where each byte corresponds to two pixels.|False|
|(True/False): In video mode 13h, each screen row uses 320 bytes of storage.|True|
|In one sentence, explain how video mode 13h sets the colors of pixels.|通过设置调色板索引和对应的 RGB 值来设置像素颜色。|
|How is the color index used in video mode 13h?|颜色索引用于从调色板中选择特定的颜色,并将其应用到视频缓冲区中的像素上。|
|In video mode 13h, what is contained in each element of the color palette?|每个调色板元素包含一个 RGB 颜色值。|
|What are the three RGB values for dark gray?|通常为(32, 32, 32)。|
|What are the three RGB values for white?|(63, 63, 63)|
|What are the three RGB values for bright red?|(63, 0, 0)|
|Challenge: Show how to set the screen background color in video mode 13h to green.|可以通过设置调色板索引对应的 RGB 值为绿色(如 0, 63, 0),并将该索引应用到整个视频缓冲区。|
|Challenge: Show how to set the screen background color in video mode 13h to white.|设置调色板索引对应的 RGB 值为白色(63, 63, 63),并将该索引应用到整个视频缓冲区。|
3. 鼠标编程基础
鼠标通常通过 PS - 2 鼠标端口、RS - 232 串口、USB 端口或无线连接到计算机主板。在检测鼠标之前,MS - DOS 需要安装设备驱动程序。鼠标的移动以“米基”(mickeys)为单位进行跟踪,1 米基约代表 1/200 英寸的物理鼠标移动距离。鼠标的米基与像素的比例可以设置,默认情况下,每 8 个水平像素对应 8 米基,每 8 个垂直像素对应 16 米基,还有一个双速阈值,默认值为每秒 64 米基。
4. 鼠标 INT 33h 函数
INT 33h 提供了关于鼠标的各种信息,包括其当前位置、最后点击的按钮、速度等,还可以用于显示或隐藏鼠标光标。以下是一些重要的 INT 33h 函数:
|函数编号|描述|接收参数|返回值|示例调用|
|----|----|----|----|----|
|0|Reset mouse and get status|AX = 0|如果支持鼠标,AX = FFFFh 且 BX = 鼠标按钮数量;否则,AX = 0|mov ax,0
int 33h
cmp ax,0
je MouseNotAvailable
mov numberOfButtons,bx|
|1|Show mouse pointer|AX = 1|无|mov ax,1
int 33h|
|2|Hide mouse pointer|AX = 2|无|mov ax,2
int 33h|
|3|Get mouse position and status|AX = 3|BX = 鼠标按钮状态
CX = X 坐标(像素)
DX = Y 坐标(像素)|mov ax,3
int 33h
test bx,1
jne Left_Button_Down
test bx,2
jne Right_Button_Down
test bx,4
jne Center_Button_Down
mov Xcoord,cx
mov yCoord,dx|
|4|Set mouse position|AX = 4
CX = X 坐标(像素)
DX = Y 坐标(像素)|无|mov ax,4
mov cx,200 ; X - position
mov dx,100 ; Y - position
int 33h|
|5|Get button press information|AX = 5
BX = 按钮 ID (0 = 左,1 = 右,2 = 中)|AX = 按钮状态
BX = 按钮按下计数器
CX = 最后按钮按下的 X 坐标
DX = 最后按钮按下的 Y 坐标|mov ax,5
mov bx,0 ; button ID
int 33h
test ax,1 ; left button down?
jz skip ; no - skip
mov X_coord,cx ; yes: save coordinates
mov Y_coord,dx|
|6|Get button release information|AX = 6
BX = 按钮 ID (0 = 左,1 = 右,2 = 中)|AX = 按钮状态
BX = 按钮释放计数器
CX = 最后按钮释放的 X 坐标
DX = 最后按钮释放的 Y 坐标|mov ax,6
mov bx,0 ; button ID
int 33h
test ax,1 ; left button released?
jz skip ; no - skip
mov X_coord,cx ; yes: save coordinates
mov Y_coord,dx|
|7|Set horizontal limits|AX = 7
CX = 最小 X 坐标(像素)
DX = 最大 X 坐标(像素)|无|mov ax,7
mov cx,100 ; set X - range to
mov dx,700 ; (100,700)
int 33h|
|8|Set vertical limits|AX = 8
CX = 最小 Y 坐标(像素)
DX = 最大 Y 坐标(像素)|无|mov ax,8
int 33h
mov cx,100 ; set Y - range to
mov dx,500 ; (100,500)
int 33h|
5. 坐标转换
在 MS - DOS 中,标准文本字体为 8 像素宽、16 像素高,因此可以通过以下公式进行像素坐标和字符坐标的转换:
- 像素坐标转字符坐标:$C = int(P / D)$,其中 $C$ 是字符坐标,$P$ 是像素坐标,$D$ 是字符尺寸。例如,假设字符宽度为 8 像素,如果 INT 33h 函数 3 返回的 X 坐标为 100 像素,则对应的字符位置为 $int(100 / 8) = 12$。
- 字符坐标转像素坐标:$P = C * D$,其中 $C$ 是字符坐标,$P$ 是像素坐标,$D$ 是字符尺寸。例如,如果字符宽度为 8 像素,要将鼠标放在字符单元格 12 中,则该单元格最左侧像素的 X 坐标为 $12 * 8 = 96$。
6. 鼠标跟踪程序
以下是一个简单的鼠标跟踪程序,用于跟踪文本鼠标光标的移动,不断更新屏幕右下角的 X 和 Y 坐标,并在用户按下左键时,在屏幕左下角显示鼠标的位置:
TITLE Tracking the Mouse (mouse.asm)
; Demonstrates basic mouse functions available via INT 33h.
; In Standard DOS mode, each character position in the DOS
; window equals 8 mouse units.
INCLUDE Irvine16.inc
GET_MOUSE_STATUS = 0
SHOW_MOUSE_POINTER = 1
HIDE_MOUSE_POINTER = 2
GET_CURSOR_SIZE = 3
GET_BUTTON_PRESS_INFO = 5
GET_MOUSE_POSITION_AND_STATUS = 3
ESCkey = 1Bh
.data
greeting BYTE "[Mouse.exe] Press Esc to quit",0
statusLine BYTE "Left button: "
BYTE "Mouse position: ",0
blanks BYTE " ",0
xCoord WORD 0
; current X-coordinate
yCoord WORD 0
; current Y-coordinate
xPress WORD 0
; X-coord of last button press
yPress WORD 0
; Y-coord of last button press
; Display coordinates.
statusRow BYTE ?
statusCol BYTE 15
buttonPressCol BYTE 20
statusCol2 BYTE 60
coordCol BYTE 65
.code
main PROC
mov ax,@data
mov ds,ax
call Clrscr
; Get the screen X/Y coordinates.
call GetMaxXY
; DH = rows, DL = columns
dec dh
; calculate status row value
mov statusRow,dh
; Hide the text cursor and display the mouse.
call HideCursor
mov dx,OFFSET greeting
call WriteString
call ShowMousePointer
; Display status information on the bottom screen line.
mov dh,statusRow
mov dl,0
call Gotoxy
mov dx,OFFSET statusLine
call Writestring
; Loop: show mouse coordinates, check for left mouse
; button press or keypress (Esc key).
L1:
call ShowMousePosition
call LeftButtonPress
; check for button press
mov ah,11h
; key pressed already?
int 16h
jz L2
; no, continue the loop
mov ah,10h
; remove key from buffer
int 16h
cmp al,ESCkey
; yes. Is it the ESC key?
je quit
; yes, quit the program
L2:
jmp L1
; no, continue the loop
; Hide the mouse, restore the text cursor, clear
; the screen, and wait for a key press.
quit:
call HideMousePointer
call ShowCursor
call Clrscr
call WaitMsg
exit
main ENDP
;---------------------------------------------------------
GetMousePosition PROC USES ax
;
; Gets the current mouse position and button status.
; Receives: nothing
; Returns: BX = button status (0 = left button down,
; (1 = right button down, 2 = center button down)
; CX = X-coordinate
; DX = Y-coordinate
;---------------------------------------------------------
mov ax,GET_MOUSE_POSITION_AND_STATUS
int 33h
ret
GetMousePosition ENDP
;---------------------------------------------------------
HideCursor PROC USES ax cx
;
; Hide the text cursor by setting its top line
; value to an illegal value.
; Receives: nothing. Returns: nothing
;---------------------------------------------------------
mov ah,GET_CURSOR_SIZE
int 10h
or ch,30h
; set upper row to illegal value
mov ah,1
; set cursor size
int 10h
ret
HideCursor ENDP
;---------------------------------------------------------
ShowCursor PROC USES ax cx
;
; Show the text cursor by setting size to default.
; Receives: nothing. Returns: nothing
;---------------------------------------------------------
mov ah,GET_CURSOR_SIZE
int 10h
mov ah,1
; set cursor size
mov cx,0607h
; default size
int 10h
ret
ShowCursor ENDP
;---------------------------------------------------------
HideMousePointer PROC USES ax
;
; Hides the mouse pointer.
; Receives: nothing. Returns: nothing
;---------------------------------------------------------
mov ax,HIDE_MOUSE_POINTER
int 33h
ret
HideMousePointer ENDP
;---------------------------------------------------------
ShowMousePointer PROC USES ax
;
; Makes the mouse pointer visible.
; Receives: nothing. Returns: nothing
;---------------------------------------------------------
mov ax,SHOW_MOUSE_POINTER ; make mouse cursor visible
int 33h
ret
ShowMousePointer ENDP
;---------------------------------------------------------
LeftButtonPress PROC
;
; Checks for the most recent left mouse button press
; and displays the mouse location.
; Receives: nothing. Returns: nothing
;---------------------------------------------------------
pusha
mov ax,GET_BUTTON_PRESS_INFO
mov bx,0
; specify the left button
int 33h
; Exit proc if the coordinates have not changed.
cmp cx,xPress
; same X coordinate?
jne L1
; no: continue
cmp dx,yPress
; same Y coordinate?
je L2
; yes: exit
; Coordinates have changed, so save them.
L1:
mov xPress,cx
mov yPress,dx
; Position the cursor, clear the old numbers.
mov dh,statusRow
; screen row
mov dl,statusCol
; screen column
call Gotoxy
push dx
mov dx,OFFSET blanks
call WriteString
pop dx
; Show coordinates where mouse button was pressed.
call Gotoxy
mov ax,xCoord
call WriteDec
mov dl,buttonPressCol
call Gotoxy
mov ax,yCoord
call WriteDec
L2:
popa
ret
LeftButtonPress ENDP
;---------------------------------------------------------
SetMousePosition PROC
;
; Set the mouse's position on the screen.
; Receives: CX = X-coordinate
; DX = Y-coordinate
; Returns: nothing
;---------------------------------------------------------
mov ax,4
int 33h
ret
SetMousePosition ENDP
;---------------------------------------------------------
ShowMousePosition PROC
;
; Get and show the mouse coordinates at the
; bottom of the screen.
; Receives: nothing
; Returns: nothing
;---------------------------------------------------------
pusha
call GetMousePosition
; Exit proc if the coordinates have not changed.
cmp cx,xCoord
; same X coordinate?
jne L1
; no: continue
cmp dx,yCoord
; same Y coordinate?
je L2
; yes: exit
; Save the new X and Y coordinates.
L1:
mov xCoord,cx
mov yCoord,dx
; Position the cursor, clear the old numbers.
mov dh,statusRow
; screen row
mov dl,statusCol2
; screen column
call Gotoxy
push dx
mov dx,OFFSET blanks
call WriteString
pop dx
; Show the mouse coordinates.
call Gotoxy
mov ax,xCoord
call WriteDec
mov dl,coordCol
; screen column
call Gotoxy
mov ax,yCoord
call WriteDec
L2:
popa
ret
ShowMousePosition ENDP
END main
该程序的行为会根据两个因素有所变化:一是所运行的 MS - Windows 版本,二是在控制台窗口还是全屏模式下运行。例如,在 Windows XP 及更高版本中,控制台窗口默认有 50 条垂直文本行。在全屏模式下,鼠标光标是一个实心块,其坐标似乎每次变化一个像素;而在控制台窗口模式下,鼠标光标是一个指针,其坐标水平方向每 8 像素、垂直方向每 16 像素变化一次。
7. 鼠标编程相关问题解答
以下是一些关于鼠标编程的常见问题及解答:
|问题|答案|
|----|----|
|Which INT 33h function resets the mouse and gets the mouse status?|Function 0|
|Write ASM statements that reset the mouse and get the mouse status.|mov ax,0
int 33h
cmp ax,0
je MouseNotAvailable
mov numberOfButtons,bx|
|Which INT 33h function shows and hides the mouse pointer?|Function 1 显示鼠标指针,Function 2 隐藏鼠标指针|
|Write ASM statements that hide the mouse pointer.|mov ax,2
int 33h|
|Which INT 33h function gets the mouse position and status?|Function 3|
|Write ASM statements that get the mouse position and store it in the variables mouseX and mouseY.|mov ax,3
int 33h
mov mouseX,cx
mov mouseY,dx|
|Which INT 33h function sets the mouse position?|Function 4|
|Write ASM statements that set the mouse pointer to X = 100 and Y = 400.|mov ax,4
mov cx,100
mov dx,400
int 33h|
|Which INT 33h function gets mouse button press information?|Function 5|
|Write ASM statements that jump to label Button1 when the left mouse button has been pressed.|mov ax,5
mov bx,0
int 33h
test ax,1
jne Button1|
|Which INT 33h function gets mouse button release information?|Function 6|
|Write ASM statements that get the mouse position at the point when the right button was released, and store the position in the variables mouseX and mouseY.|mov ax,6
mov bx,1
int 33h
mov mouseX,cx
mov mouseY,dx|
|Write ASM statements that set the vertical limits of the mouse to 200 and 400.|mov ax,8
mov cx,200
mov dx,400
int 33h|
|Write ASM statements that set the horizontal limits of the mouse to 300 and 600.|mov ax,7
mov cx,300
mov dx,600
int 33h|
通过以上内容,我们对 BIOS 级编程中的像素绘制、颜色设置以及鼠标编程有了更深入的了解。无论是简单的像素绘制,还是复杂的鼠标跟踪程序,都离不开对相关函数和算法的掌握。希望这些内容能帮助你在编程实践中更好地运用这些知识。
BIOS 级编程与鼠标编程详解
8. 鼠标编程的其他功能
除了前面介绍的主要 INT 33h 函数外,还有一些其他有用的鼠标编程功能,以下是这些功能的详细介绍:
|函数编号|描述|输入/输出参数|
|----|----|----|
|AX = 0Fh|Sets the number of mickeys per 8 pixels for horizontal and vertical mouse motion.|接收:CX = 水平米基数,DX = 垂直米基数。默认值为 CX = 8,DX = 16。|
|AX = 10h|Set mouse exclusion area (prevents mouse from entering a rectangle).|接收:CX, DX = 左上角的 X, Y 坐标。SI, DI = 右下角的 X, Y 坐标|
|AX = 13h|Set double speed threshold.|接收:DX = 双速阈值(米基/秒),默认值为 64|
|AX = 1Ah|Set mouse sensitivity and threshold.|接收:BX = 水平速度(米基/秒),CX = 垂直速度(米基/秒),DX = 双速阈值(米基/秒)|
|AX = 1Bh|Get mouse sensitivity and threshold.|返回:BX = 水平速度,CX = 垂直速度,DX = 双速阈值|
|AX = 1Fh|Disable mouse driver.|返回:如果失败,AX = FFFFh|
|AX = 20h|Enable mouse driver.|无|
|AX = 24h|Get mouse information.|错误时返回 FFFFh;否则,返回:BH = 主版本号,BL = 次版本号,CH = 鼠标类型 (1 = 总线,2 = 串口,3 = InPort,4 = PS/2,5 = HP);CL = IRQ 号(PS/2 鼠标为 0)|
9. 鼠标编程流程总结
下面通过一个 mermaid 流程图来总结鼠标编程的基本流程:
graph TD
A[初始化] --> B[检测鼠标支持]
B -- 支持 --> C[显示鼠标指针]
B -- 不支持 --> D[提示错误并退出]
C --> E[循环检测鼠标事件]
E --> F{是否有按键按下}
F -- 是 --> G[处理按键事件]
F -- 否 --> H{是否有鼠标移动}
H -- 是 --> I[更新鼠标位置显示]
H -- 否 --> E
G --> E
I --> E
10. 鼠标编程的实际应用场景
鼠标编程在很多实际场景中都有应用,以下是一些常见的应用场景:
-
游戏开发
:在游戏中,鼠标可以用于控制角色的移动、攻击、选择物品等操作。通过鼠标编程,可以实现精确的鼠标交互,提升游戏的用户体验。
-
图形设计软件
:图形设计软件需要用户通过鼠标进行绘图、选择工具、调整图形等操作。鼠标编程可以实现对鼠标事件的精确处理,满足图形设计的需求。
-
用户界面设计
:在各种软件的用户界面中,鼠标可以用于点击按钮、拖动窗口、选择菜单项等操作。鼠标编程可以实现流畅的用户界面交互,提高软件的易用性。
11. 鼠标编程的注意事项
在进行鼠标编程时,需要注意以下几点:
-
兼容性问题
:不同的操作系统和硬件平台可能对鼠标编程的支持有所不同。在编写代码时,需要考虑兼容性问题,确保程序在不同环境下都能正常运行。
-
性能优化
:鼠标事件的处理可能会对系统性能产生一定的影响。在编写代码时,需要注意性能优化,避免出现卡顿或响应不及时的情况。
-
错误处理
:在鼠标编程过程中,可能会出现各种错误,如鼠标驱动未安装、鼠标设备故障等。在编写代码时,需要进行错误处理,确保程序在出现错误时能够给出合理的提示。
12. 总结
本文详细介绍了 BIOS 级编程中的像素绘制、颜色设置以及鼠标编程的相关知识。通过对视频模式 13h 的了解,我们可以实现像素的绘制和颜色的设置;通过对 INT 33h 函数的掌握,我们可以实现鼠标的各种操作,如检测鼠标状态、显示/隐藏鼠标指针、获取鼠标位置等。同时,我们还介绍了鼠标编程的其他功能、流程总结、实际应用场景以及注意事项。希望这些内容能帮助你在编程实践中更好地运用这些知识,实现更复杂的鼠标交互功能。
通过以上内容,我们对 BIOS 级编程和鼠标编程有了全面的认识。无论是初学者还是有一定经验的开发者,都可以从这些知识中获得启发,进一步提升自己的编程能力。在实际应用中,我们可以根据具体需求,灵活运用这些知识,开发出更加实用和高效的程序。
超级会员免费看
53

被折叠的 条评论
为什么被折叠?



