есть ли способ прочитать клавиши-модификаторы клавиатуры, такие как ALT или CTRL, в программах на базе DOS?
Я знаю, что вы можете опросить буфер клавиатуры, чтобы получить ключи-модификаторы, такие как ALT или CTRL. Но даже в старых программах DOS было действие, когда я просто нажимал эти клавиши (например, чтобы изменить цвет кнопок MENU, нажав ALT). Есть ли в DOS способ получить эти ключи? Как это сделать? Я думаю, что в BASIC не будет решения, хотя BASIC имеет доступный обработчик событий ON. Любые рекомендации или советы по этому вопросу приветствуются.
2 ответа
Вы можете посмотреть KeyboardStatusFlags по линейному адресу 1047 в области данных BIOS. Для 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
Отвечая на комментарий
Есть ли способ получить КЛЮЧ (ЗНАЧЕНИЕ ASCII), просмотрев адрес?
Опять же, вы можете найти эту информацию в буфере клавиатуры (кольцевой буфер). BIOS поддерживает указатель размером со слово на место, где хранится следующий доступный ключ (HEAD), и указатель размером со слово на место за местом, где хранится последний буферизованный ключ (TAIL). Если HEAD равен TAIL, буфер клавиатуры пуст.INKEY$
в этом случае вернет пустую строку.
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
"Преимущество" приведенного выше кода в том, что вы можете предварительно просмотреть, какая клавиша (если есть) будет следующей в буфере клавиатуры. Ключ не снимается.INKEY$
может предоставить ту же информацию, но также удалит ключ.
Другое решение - ответ Майкла Петча: Stackru-get ASCII VALUE
; 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 Assembler:
; 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 Basic:
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