编程语言:8086汇编中int 16h接收alt+方向键

在8086汇编编程中,遇到int 16h无法捕获Alt+方向键组合的问题。作者采用循环读取按键状态的方法来替代,通过检测alt键(通码38h,断码b8h)与方向键(左4bh,右4dh,上48h,下50h)的组合实现光标移动。按Esc键可退出程序。期待读者提供int 16h不支持此组合键的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天一个网友在一个汇编群里问了一个问题,内容差不多就是,如何在8086汇编中用int 16h号中断接收alt+方向键(用这个组 合键移动光标)。

然后我试了一下,发现,int 16h对这个组合键没反应。

然后我没找到原因,不过找了个替补方法,就是用一直循环用int al,60h读取当前按下的键,判断是不是我需要的键。

下面方向键都为扫描码:
alt键的通码是38h,断码是b8h。左方向键是4bh,右方向键是4dh,上方向键是48h,下方向键是50h。

 

代码:

 

assume cs:code,ds:data,ss:stack

stack segment
	db 256 dup (0)
stack ends

data segment
	var_x db 0
	var_y db 0
	db 256 dup (0)
data ends

code segment
start:
	mov ax,stack
	mov ss,ax
	mov sp,256
	mov ax,data
	mov ds,ax
	
	;置光标
	mov ah,2
	mov bh,0
	mov dh,var_y
	mov dl,var_x
	int 10h
	
	loopstart1:
		in al,60h
		
		cmp al,38h
		je loopstart2
		cmp al,01h
		je finishloopstart1
		jmp loopstart1end
		
		loopstart2:
			in al,60h
			cmp al,0b8h
			je finishloopstart2
			cmp al,50h
			je down
			cmp al,48h
			je up
			cmp al,4bh
			je left
			cmp al,4dh
			je right
			jmp loopstart2end
			
			left:
			dec var_x
			mov ah,2
			mov bh,0
			mov dh,var_y
			mov dl,var_x
			int 10h
			jmp loopstart2end
			
			right:
			inc var_x
			mov ah,2
			mov bh,0
			mov dh,var_y
			mov dl,var_x
			int 10h
			jmp loopstart2end
			
			up:
			dec var_y
			mov ah,2
			mov bh,0
			mov dh,var_y
			mov dl,var_x
			int 10h
			jmp loopstart2end
			
			down:
			inc var_y
			mov ah,2
			mov bh,0
			mov dh,var_y
			mov dl,var_x
			int 10h
			jmp loopstart2end
			
			loopstart2end:
			call far ptr fun_delay
			
		jmp loopstart2
		finishloopstart2:
		loopstart1end:
	jmp loopstart1
	finishloopstart1:
	
	mov ax,4c00h
	int 21h

;延迟功能,自己设置dx和ax的值改变时间
fun_delay:
	push ax
	push dx
	mov dx,0h
	mov ax,0ffffh
	fun_delay_b:
		add ax,0
		je fun_delay_a
		dec ax
		jmp fun_delay_b
		fun_delay_a:
		add dx,0
		je fun_delay_c
		dec dx
		mov ax,0ddddh
	jmp fun_delay_b
	fun_delay_c:
	pop dx
	pop ax
	retf
	
code ends
end start

功能:
你按alt+方向键可以往各个方向移动光标(没有检测超界),按esc可退出程序。

 

自然语言描述如下:

循环1开始
	读60h端口中的数据
	如果60h端口中的数据等于38h,就开始执行循环2,否则就跳到循环1开始
	循环2开始
		读60h端口中的数据
		如果60h端口中的数据等于b8h,就说明已经松开alt键,这时跳到循环1开始
		如果60h端口中的数据等于4bh,就将光标向左移动
		如果60h端口中的数据等于4dh,就将光标向右移动
		如果60h端口中的数据等于48h,就将光标向上移动
		如果60h端口中的数据等于50h,就将光标向下移动
	跳到循环2开始
跳到循环1开始

 

差不多就这个样子吧。

大家如果发现为啥int 16h不能接收alt+方向键的原因,可以与我分享下,我在这就谢谢各位了。

; 电子秒表程序 - MASM实现 ; 功能: 显示秒和毫秒(1-60秒),支持开始/暂停/复位/退出 .MODEL SMALL .STACK 100h .DATA ; 时间变量 start_time DW 0, 0 ; 开始时间的时钟计数(高位:低位) current_time DW 0, 0 ; 当前时间的时钟计数 paused_duration DW 0, 0 ; 暂停期间的时间累计 paused DB 0 ; 暂停状态(0=运行,1=暂停) ; 显示变量 seconds DW 0 ; 秒数 milliseconds DW 0 ; 毫秒数 time_string DB '00:000', '$' ; 时间显示字符串 ; 提示信息 initial_msg DB 'Electronic Stopwatch (MASM)', 0Dh, 0Ah DB 'Press:', 0Dh, 0Ah DB 'S - Start/Pause', 0Dh, 0Ah DB 'R - Reset', 0Dh, 0Ah DB 'Q - Quit', 0Dh, 0Ah, '$' running_msg DB 'Running...', 0Dh, 0Ah, '$' paused_msg DB 'Paused. Press S to continue.', 0Dh, 0Ah, '$' .CODE MAIN PROC MOV AX, @DATA MOV DS, AX ; 初始化显示 CALL init_proc ; 主循环 main_loop: ; 检查键盘输入 CALL check_keyboard ; 如果暂停则跳过时间更新 CMP paused, 1 JE main_loop ; 获取当前时间 MOV AH, 00h INT 1Ah MOV current_time[0], DX MOV current_time[2], CX ; 计算时间差 CALL calculate_time ; 更新显示 CALL update_display ; 延迟以避免闪烁 MOV CX, 01h MOV DX, 0FFFFh MOV AH, 86h INT 15h JMP main_loop ; 退出程序 exit_program: MOV AX, 4C00h INT 21h MAIN ENDP ; 初始化过程 init_proc PROC ; 清屏 MOV AX, 0600h MOV BH, 07h MOV CX, 0000h MOV DX, 184Fh INT 10h ; 设置光标位置(显示提示信息) MOV AH, 02h MOV BH, 00h MOV DH, 10 ; 行 MOV DL, 25 ; 列 INT 10h ; 显示初始信息 LEA DX, initial_msg MOV AH, 09h INT 21h ; 设置光标位置(显示时间) MOV AH, 02h MOV BH, 00h MOV DH, 12 ; 行 MOV DL, 35 ; 列 INT 10h ; 显示初始时间 MOV seconds, 0 MOV milliseconds, 0 CALL update_display RET init_proc ENDP ; 检查键盘输入 check_keyboard PROC MOV AH, 01h ; 检查键盘状态 INT 16h JZ no_key ; 无按键则返回 MOV AH, 00h ; 读取按键 INT 16h CMP AL, 'S' ; 暂停/继续 JE toggle_pause CMP AL, 's' JE toggle_pause CMP AL, 'R' ; 复位 JE reset_timer CMP AL, 'r' JE reset_timer CMP AL, 'Q' ; 退出 JE exit_program CMP AL, 'q' JE exit_program no_key: RET toggle_pause: CMP paused, 1 JE unpause ; 暂停计时 MOV paused, 1 ; 记录暂停开始时间 MOV AH, 00h INT 1Ah MOV paused_duration[0], DX MOV paused_duration[2], CX ; 显示暂停信息 MOV AH, 02h MOV BH, 00h MOV DH, 14 ; 行 MOV DL, 25 ; 列 INT 10h LEA DX, paused_msg MOV AH, 09h INT 21h RET unpause: ; 继续计时 MOV paused, 0 ; 计算暂停持续时间并累加到paused_duration MOV AH, 00h INT 1Ah SUB DX, paused_duration[0] SBB CX, paused_duration[2] ADD paused_duration[0], DX ADC paused_duration[2], CX ; 清除暂停信息 MOV AX, 0600h MOV BH, 07h MOV CX, 0E00h MOV DX, 0E4Fh INT 10h RET reset_timer: ; 复位计时器 MOV seconds, 0 MOV milliseconds, 0 ; 重置开始时间 MOV AH, 00h INT 1Ah MOV start_time[0], DX MOV start_time[2], CX ; 重置暂停持续时间 MOV paused_duration[0], 0 MOV paused_duration[2], 0 ; 更新显示 CALL update_display RET exit_program: ; 退出程序(通过主程序中的跳转实现) RET check_keyboard ENDP ; 计算时间差 calculate_time PROC ; 计算当前时间与开始时间的差值 MOV AX, current_time[0] SUB AX, start_time[0] MOV DX, current_time[2] SBB DX, start_time[2] ; 减去暂停期间的时间 SUB AX, paused_duration[0] SBB DX, paused_duration[2] ; 转换为秒和毫秒 ; 时钟计数每秒约18.2次(每个计数约55ms) ; 计算秒数 (DX:AX / 18.2) ; 近似计算: 18.2 ≈ 182/10 ; 所以 count / 18.2 ≈ count * 10 / 182 ; 保存原始计数 PUSH DX PUSH AX ; 计算 count * 10 MOV BX, 10 MUL BX ; AX = low * 10 MOV CX, DX ; 保存高位结果 MOV DX, AX ; DX = low * 10 POP AX ; 恢复原始AX POP BX ; 原始DX在BX中 PUSH DX ; 保存低位结果 MOV AX, BX ; AX = 原始DX MOV BX, 10 MUL BX ; AX = high * 10 POP DX ; 恢复低位结果 ADD DX, AX ; DX:AX = count * 10 ; 现在除以182得到秒数 MOV BX, 182 DIV BX ; AX = 秒数, DX = 余数 ; 确保不超过60秒 CMP AX, 60 JLE store_seconds MOV AX, 60 store_seconds: MOV seconds, AX ; 计算毫秒数: 余数 * 1000 / 182 MOV AX, DX ; 余数 MOV BX, 1000 MUL BX ; DX:AX = 余数 * 1000 MOV BX, 182 DIV BX ; AX = 毫秒数 MOV milliseconds, AX RET calculate_time ENDP ; 更新显示 update_display PROC ; 转换秒数为ASCII MOV AX, seconds MOV BX, 10 XOR DX, DX DIV BX ; AX = 十位, DX = 个位 ADD AL, '0' MOV time_string[0], AL ADD DL, '0' MOV time_string[1], DL ; 转换毫秒数为ASCII MOV AX, milliseconds MOV BX, 100 XOR DX, DX DIV BX ; AX = 百位, DX = 余数 ADD AL, '0' MOV time_string[3], AL MOV AX, DX MOV BX, 10 XOR DX, DX DIV BX ; AX = 十位, DX = 个位 ADD AL, '0' MOV time_string[4], AL ADD DL, '0' MOV time_string[5], DL ; 设置光标位置 MOV AH, 02h MOV BH, 00h MOV DH, 12 ; 行 MOV DL, 35 ; 列 INT 10h ; 显示时间字符串 LEA DX, time_string MOV AH, 09h INT 21h RET update_display ENDP END MAIN 我在按键识别上有问题(识别不出来),可能是 INT 16h的问题,能否帮我单独修改这里
最新发布
06-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值