有没有办法在基于 DOS 的程序中读取键盘修改键,例如 ALT 或 CTRL?
is there a way to read the Keyboard Modifier Key such as ALT or CTRL in DOS-Based Progarmms?
我知道您可能会轮询键盘缓冲区以获取修改键,例如 ALT 或 CTRL。但即使在旧的 DOS 程序中,当我按下这些键时也会有一个动作(f.e。通过按下 ALT 来更改菜单按钮的颜色)。在 DOS 中有没有办法获得这些密钥?这是怎么做到的?我认为在 BASIC 中没有解决方案,尽管 BASIC 有一些可用的 ON Eventhandler。欢迎对这个问题提出任何建议。
可以查看BIOS数据区线性地址1047处的KeyboardStatusFlags。对于 Alt 键,您检查位 3,对于 Ctrl 键,您检查位 2。下一个 QBASIC 程序正是这样做的:
DEF SEG = 0
DO
IF PEEK(1047) AND 8 THEN
PRINT "ALT is pressed"
EXIT DO
ELSEIF PEEK(1047) AND 4 THEN
PRINT "CTRL is pressed"
EXIT DO
END IF
LOOP
正在回复评论
Is there also a way to get the KEY Pressed (ASCII VALUE) by peeking an address?
您可以再次在键盘缓冲区(循环缓冲区)中找到此信息。 BIOS 维护一个指向下一个可用密钥存储位置 (HEAD) 的 word-sized 指针,以及一个指向最近缓冲密钥存储位置 (TAIL) 后面的 word-sized 指针。如果 HEAD 等于 TAIL,则键盘缓冲区为空。在这种情况下,INKEY$
会 return 一个空字符串。
Head% = PEEK(1050) + 256 * PEEK(1051)
Tail% = PEEK(1052) + 256 * PEEK(1053)
IF Head% <> Tail% THEN
Ascii% = PEEK(1024 + Head%)
Scan% = PEEK(1024 + Head% + 1)
ELSE
Ascii% = 0
Scan% = 0
END IF
上面代码的'advantage'是你可以预览键盘缓冲区中下一个可用的键(如果有的话)。密钥未被删除。 INKEY$
可以提供相同的信息 但也会删除密钥。
另一种解决方案是 Michael Petch 的回答:
; Assemble with nasm -f bin getkeyh.asm -o getkeyh.com
GetKeyH:
push bp
mov bp, sp
les bx, [bp+6] ; ES:BX = address of variable to return value in
; [bp+0] is where BP was pushed
; [bp+2] is where the 32-bit far return address is
; [bp+6] is where last parameter is
; Parameters are pushed on stack left to right
; like pascal calling convention.
in al,60h ; Get scancode from keyboard
xchg dx,ax
xor ax,ax ; assume no key (AX=0)
test dl,10000000b ; is it key up event?
jnz short getkeyhD ; if it is return 0 (in AX)
mov al, dl ; Otherwise keydown, AX = scan code
getkeyhD:
mov [es:bx], ax ; Update variable with scancode so BASIC can read it.
pop bp
可以与 MASM/JWASM/Turbo 汇编程序一起使用的版本:
; Assemble and link with Turbo Assembler to getkeyh.com file with:
; tasm getkeyh.asm
; tlink /t getkeyh
;
; You can use JWASM a MASM clone available on MacOS/Linux/Windows to
; build getkeyh.com . You can use:
; jwasm -bin -Fo=getkeyh.com -0 getkeyh.asm
;
; -0 generates code that can run on 8088/8086 processors
; -1 for 186+ processors
; -2 for 286+ processors
;
; MASM 6.0+ and Segmented Linker LINK.EXE (5.60) can generate getkeyh.com:
; masm getkeyh.asm;
; link /t getkeyh,getkeyh.com;
;
; MASM5.x doesn't support ".model tiny" you have to use ".model small"
; and use LINK.EXE 5.60:
; masm getkeyh.asm;
; link /t getkeyh,getkeyh.com;
.model tiny ; We will generate a COM file
.code
org 100h ; COM Programs have an ORG 100h
GetKeyH PROC
push bp
mov bp, sp
les bx, [bp+6] ; ES:BX = address of variable to return value in
; [bp+0] is where BP was pushed
; [bp+2] is where the 32-bit far return address is
; [bp+6] is where last parameter is
; Parameters are pushed on stack left to right
; like pascal calling convention.
in al,60h ; Get scancode from keyboard
xchg dx,ax
xor ax,ax ; assume no key (AX=0)
test dl,10000000b ; is it key up event?
jnz short getkeyhD ; if it is return 0 (in AX)
mov al, dl ; Otherwise keydown, AX = scan code
getkeyhD:
mov es:[bx], ax ; Update var with scancode so Turbo Basic can read it
pop bp ; Do not use `RET`, Turbo Basic will return for us
GetKeyH ENDP
END GetKeyH ; Entrypoint is GetKeyH
Turbo 基础程序部分:
SUB GetKeyH INLINE
$INLINE "getkeyh.com"
END SUB
CLS
DO
LOCATE 10, 10
Call GetKeyH (scancode%)
PRINT "Key = "; HEX$(scancode%); " "
LOOP UNTIL INKEY$ = CHR$(27)
END
我知道您可能会轮询键盘缓冲区以获取修改键,例如 ALT 或 CTRL。但即使在旧的 DOS 程序中,当我按下这些键时也会有一个动作(f.e。通过按下 ALT 来更改菜单按钮的颜色)。在 DOS 中有没有办法获得这些密钥?这是怎么做到的?我认为在 BASIC 中没有解决方案,尽管 BASIC 有一些可用的 ON Eventhandler。欢迎对这个问题提出任何建议。
可以查看BIOS数据区线性地址1047处的KeyboardStatusFlags。对于 Alt 键,您检查位 3,对于 Ctrl 键,您检查位 2。下一个 QBASIC 程序正是这样做的:
DEF SEG = 0
DO
IF PEEK(1047) AND 8 THEN
PRINT "ALT is pressed"
EXIT DO
ELSEIF PEEK(1047) AND 4 THEN
PRINT "CTRL is pressed"
EXIT DO
END IF
LOOP
正在回复评论
Is there also a way to get the KEY Pressed (ASCII VALUE) by peeking an address?
您可以再次在键盘缓冲区(循环缓冲区)中找到此信息。 BIOS 维护一个指向下一个可用密钥存储位置 (HEAD) 的 word-sized 指针,以及一个指向最近缓冲密钥存储位置 (TAIL) 后面的 word-sized 指针。如果 HEAD 等于 TAIL,则键盘缓冲区为空。在这种情况下,INKEY$
会 return 一个空字符串。
Head% = PEEK(1050) + 256 * PEEK(1051)
Tail% = PEEK(1052) + 256 * PEEK(1053)
IF Head% <> Tail% THEN
Ascii% = PEEK(1024 + Head%)
Scan% = PEEK(1024 + Head% + 1)
ELSE
Ascii% = 0
Scan% = 0
END IF
上面代码的'advantage'是你可以预览键盘缓冲区中下一个可用的键(如果有的话)。密钥未被删除。 INKEY$
可以提供相同的信息 但也会删除密钥。
另一种解决方案是 Michael Petch 的回答:
; Assemble with nasm -f bin getkeyh.asm -o getkeyh.com
GetKeyH:
push bp
mov bp, sp
les bx, [bp+6] ; ES:BX = address of variable to return value in
; [bp+0] is where BP was pushed
; [bp+2] is where the 32-bit far return address is
; [bp+6] is where last parameter is
; Parameters are pushed on stack left to right
; like pascal calling convention.
in al,60h ; Get scancode from keyboard
xchg dx,ax
xor ax,ax ; assume no key (AX=0)
test dl,10000000b ; is it key up event?
jnz short getkeyhD ; if it is return 0 (in AX)
mov al, dl ; Otherwise keydown, AX = scan code
getkeyhD:
mov [es:bx], ax ; Update variable with scancode so BASIC can read it.
pop bp
可以与 MASM/JWASM/Turbo 汇编程序一起使用的版本:
; Assemble and link with Turbo Assembler to getkeyh.com file with:
; tasm getkeyh.asm
; tlink /t getkeyh
;
; You can use JWASM a MASM clone available on MacOS/Linux/Windows to
; build getkeyh.com . You can use:
; jwasm -bin -Fo=getkeyh.com -0 getkeyh.asm
;
; -0 generates code that can run on 8088/8086 processors
; -1 for 186+ processors
; -2 for 286+ processors
;
; MASM 6.0+ and Segmented Linker LINK.EXE (5.60) can generate getkeyh.com:
; masm getkeyh.asm;
; link /t getkeyh,getkeyh.com;
;
; MASM5.x doesn't support ".model tiny" you have to use ".model small"
; and use LINK.EXE 5.60:
; masm getkeyh.asm;
; link /t getkeyh,getkeyh.com;
.model tiny ; We will generate a COM file
.code
org 100h ; COM Programs have an ORG 100h
GetKeyH PROC
push bp
mov bp, sp
les bx, [bp+6] ; ES:BX = address of variable to return value in
; [bp+0] is where BP was pushed
; [bp+2] is where the 32-bit far return address is
; [bp+6] is where last parameter is
; Parameters are pushed on stack left to right
; like pascal calling convention.
in al,60h ; Get scancode from keyboard
xchg dx,ax
xor ax,ax ; assume no key (AX=0)
test dl,10000000b ; is it key up event?
jnz short getkeyhD ; if it is return 0 (in AX)
mov al, dl ; Otherwise keydown, AX = scan code
getkeyhD:
mov es:[bx], ax ; Update var with scancode so Turbo Basic can read it
pop bp ; Do not use `RET`, Turbo Basic will return for us
GetKeyH ENDP
END GetKeyH ; Entrypoint is GetKeyH
Turbo 基础程序部分:
SUB GetKeyH INLINE
$INLINE "getkeyh.com"
END SUB
CLS
DO
LOCATE 10, 10
Call GetKeyH (scancode%)
PRINT "Key = "; HEX$(scancode%); " "
LOOP UNTIL INKEY$ = CHR$(27)
END