📄 keyint3.asm
字号:
;
; CW : Character Windows Drivers
;
; keyint3.asm : DOS 3 key interrupt
;
;----------------------------------------------------------------------------
; Code space constants
staticD lpsslBios,417H ;* BIOS shift state 0040:0017 !!!!
; Code space data! Horrors!
staticD pfnOldInt15,0 ; old int 15 handler
;----------------------------------------------------------------------------
;********** EnableKeyboardKbd **********
;* entry: pinkb => INKB data
;* fEnable => whether to enable or disable
;* fExiting => exiting if !fEnable
;* * enable or disable the keyboard handler
;* exit : n/a
cProc EnableKeyboardKbd, <FAR, PUBLIC, ATOMIC>, <DI>
parmDP pinkb
parmW fEnable
parmW fExiting
cBegin EnableKeyboardKbd
;* * save pointer to INKB data
mov di,OFF_lpwDataKbd ;* Data in data segment
mov bx,pinkb
mov [di].pinkbCur,bx
mov ax,fEnable
mov [bx].fPollKeyboardInkb,ax ;* to poll or not to poll?
or ax,ax
jnz enable_keyboard
jmp disable_keyboard
enable_keyboard:
;* * Enable the keyboard
test [di].fKeyboardEnabled,0ffh
jz enable_keyboard2
jmp end_enable_keyboard ;* already enabled
enable_keyboard2:
;* * Initialize globals
;; mov [di].semCopyQueue,-1
lea ax,[di].rglKbBuffer
mov [di].queueKb+pStartQueue,ax
mov [di].queueKb+pHeadQueue,ax
mov [di].queueKb+pTailQueue,ax
add ax,clKbdBuff * 4 ;* point to end
mov [di].queueKb+pEndQueue,ax
mov [di].queueKb+semQueue,-1 ; initialize both semaphores
;* * set globals to reflect initial state AND
;* * query to see if TSR is present
mov ax,tsrcInitTerm
mov [di].fKeyboardEnabled,al ;* enabled
mov bx,[di].pinkbCur
mov [bx].fKeyIsUpInkb,al ;* set up state
IFDEF WORDTSR
;* Word protocal
mov ax,55FFh
mov bx,5
xor cx,cx
int 16H
xor ax,4D53h
jnz @F
mov bx,[di].pinkbCur
mov [bx].fNormalKeyboardInkb,ax ;* 0 => proper TSR present
@@:
ELSE ;!WORDTSR
;* Works (default) protocal
lea cx,[di].wTsrRepeat ;* DS:CX => two flags
Assert <verTsr EQ 0>
xor dx,dx
mov bx,drvOffset TsrRequest
push cs
pop es ;* es:bx => TsrRequest
int 16H ;* nothing to return
xor ax,ackTsr ;* acknowledge ?
mov bx,[di].pinkbCur
mov [bx].fNormalKeyboardInkb,ax ;* 0 => proper TSR present
ENDIF ;!WORDTSR
;* * Hook the INT 1B handler
mov al, 1Bh
mov bx, pfnOldInt1B ;* offset into KBD data
mov dx, drvOffset Int1BHandler
cCall Hooker
mov bx,[di].pinkbCur
mov cx,[bx].fNormalKeyboardInkb
jcxz end_enable_keyboard
;* * Hook and initialize the INT 08 handler
mov al, 08h
mov bx, pfnOldInt08
mov dx, drvOffset Int08Handler
cCall Hooker
mov [di].rstCur, RST_IDLE
mov [di].ckeyRepeat, 0
;* * Hook INT 16
mov al, 16h
mov bx, pfnOldInt16
mov dx, drvOffset Int16Handler
cCall Hooker
mov [di].fUnhook16, 0
;* * Hook INT 9 (TSR not present)
mov al, 09h
mov bx, pfnOldInt09
mov dx, drvOffset Int09Handler
cCall Hooker
call HookInt15
les bx,lpsslBios
mov al,es:[bx]
mov [di].sslMirror,al
mov byte ptr [di].ssLastInt,al ;* set low byte only
;* * check for extended (ronco) keyboard
mov [di].pmpscvwPlain,drvOffset mpscvwPlain
mov [di].pmpscvwShift,drvOffset mpscvwShift
IFNDEF TANDY_1000 ;* don't have to worry about this
test byte ptr es:[KbType],10H
jz not_ronco ;* not extended
mov bx,[di].pinkbCur
cmp [bx].fDisableExtendedInkb,0
jne not_ronco ;* not allowed
mov [di].Int16_CmdBase,10H
mov [di].pmpscvwPlain,drvOffset mpscvwPlainRonco
mov [di].pmpscvwShift,drvOffset mpscvwShiftRonco
ENDIF ; !TANDY_1000
not_ronco:
end_enable_keyboard:
cEnd EnableKeyboardKbd
;* * Disable keyboard *
disable_keyboard:
test [di].fKeyboardEnabled,0ffh
jz end_enable_keyboard
mov [di].fKeyboardEnabled,0
;* * disable TSRs (even if they did not register with us)
IFDEF WORDTSR
;* inform of departure
mov ax,55FFh
mov bx,5
mov cx,1
int 16H
ELSE ;!WORDTSR
mov ax,tsrcInitTerm
mov dx,verTsrTerm ;* signal termination
xor bx,bx
cmp fExiting,0
jne exiting_forever
inc bx
exiting_forever:
int 16H ;* nothing to return
ENDIF ;!WORDTSR
;* * remove hooks
push ds
mov bx,[di].pinkbCur
mov cx,[bx].fNormalKeyboardInkb
lds dx,[di].pfnOldInt1B
mov ax,251BH
int 21H
jcxz int9_not_hooked
lds dx,ss:[di].pfnOldInt08 ;* get old int 08 handler
mov ax, 2508h
int 21h
lds dx,ss:[di].pfnOldInt09 ;* get old int 9 handler
mov ax,2509H
int 21H
lds dx,ss:[di].pfnOldInt16
mov ax, 2516h
int 21h
cmp ss:[di].fInt15_4F_Supported,0
je int15_not_hooked
lds dx,pfnOldInt15 ;* get old int 15 handler
mov ax,2515H
int 21H
int15_not_hooked:
int9_not_hooked:
pop ds
jmp short end_enable_keyboard
;----------------------------------------------------------------------------
;
; ::: Decide if we're going to hook int15 (to watch for int9 4F callback) :::
;
; On the PS/2, it's risky to directly poll the keyboard with IN AL,60.
; The BIOS int9 provides a solution; it performs an int15 w/AH=4F and AL=
; the scan code. An application can hook int15/4F and see the scan code
; without doing the direct polling.
;
; The only app we've seen that actually \required/ this was Word 4.0. If
; you hold down the Alt key and roll the mouse around, Word 4.0 goes bongos.
; The int15/4F callback was implemented for Word 4.00A.
;
;;; We decided with Word 4.00A to only implement the callback with
;;; DOS >= 3.30 but not 4.x. This may be overly restrictive, but it
;;; guarentees we catch all the PS/2s, which was the intent.
;
; We had decided the above. But with MS-DOS 4.0 that changed, and we now
; implement for it also, meaning for all DOS >= 3.30.
;
; Note that if any TSR grabs int9 and does the IN AL,60, we're suspect to the
; same behaviour even if we're using the callback method. The UB Network
; software is an example.
HookInt15:
mov ax,3000h
mov [di].fInt15_4F_Supported,al
int 21h
xchg ah,al
cmp ax,031Eh ; If DOS < 3.30, then don't hook.
jb NoInt15
mov ax,0C000h
int 15h ; Get system configuration parms.
jc NoInt15 ; According to PS/2 BIOS TechRef:
or ah,ah ; support -> NC and AH == 0
jnz NoInt15 ; nonsupport -> CY and AH != 0
test byte ptr es:[bx+5],00010000b ; If kbd intercept sequence
jz NoInt15 ; is alive, install our Int15
mov ax,3515h
int 21h
mov word ptr pfnOldInt15,bx ; Should use CS override.
mov word ptr pfnOldInt15+2,es
push ds
push cs
pop ds
mov dx,drvOffset Int15Handler
mov ax,2515h
int 21H
pop ds
dec [di].fInt15_4F_Supported
NoInt15:
ret
;---------------------------------
; Hooker
; Hooks an interrupt and saves the old handler's address in [DI].bx
;
; entry: AL = interrupt number
; BX = kbd data offset of dword to contain old address
; DX = drvOffset of new handler
;
cProc Hooker, <NEAR, ATOMIC>
cBegin Hooker
AssertEQ di, OFF_lpwDataKbd
push dx
push ax
push bx
mov ah, 35h
int 21h
mov ax, bx
pop bx
add bx, di
mov [bx], ax
mov [bx+2], es
pop ax
mov ah, 25h
pop dx
push ds
push cs
pop ds
int 21h
pop ds
cEnd Hooker
;----------------------------------------------------------------------------
;
; TsrRequest
;
; entry : AH = request code
; * called by TSR programs to request action
; exit : n/a (trashes normal registers)
cProc TsrRequest, <FAR, ATOMIC>, <DS, DI>
cBegin TsrRequest
mov cx,SEG_lpwDataKbd
mov ds,cx
mov di,OFF_lpwDataKbd ;* Data in data segment
mov bx,[di].pinkbCur
;* * DS:DI => data, DS:BX => INKB
cmp ah,tsrrIgnoreAltUp
jne not_ignore_altup
mov [bx].fNonAltKeyHitInkb,1 ;* => ignore next
not_ignore_altup:
cmp ah,tsrrAbort
je tsr_special_abort
end_tsr_request_poll:
;* * after any request, poll the TSR
mov [bx].fPollKeyboardInkb,1
end_tsr_request_nopoll:
cEnd TsrRequest
tsr_special_abort:
;* * we have an escape key
cCall [bx].lpfnSpecialAbortInkb ;* call SpecialTsrAbort
jmp short end_tsr_request_nopoll
;----------------------------------------------------------------------------
;
; Int1BHandler()
;
; INT 1B is invoked when the ROM BIOS sees CTRL-BREAK.
; We hook this interrupt so that DOS never sees the CTRL-BREAK.
;
; Inputs: none.
; Outputs: none.
; Uses: none, everything is saved.
Int1BHandler:
IFDEF KBD_CTRL_C_ABORT
push ds
push di
push ax
mov ax,SEG_lpwDataKbd
mov ds,ax
mov di,OFF_lpwDataKbd ;* Data in data segment
mov di,[di].pinkbCur ;* point to INKB
mov [di].fAbortInkb,1 ;* Weird Abort (no message)
pop ax
pop di
pop ds
ENDIF
iret
;----------------------------------------------------------------------------
;
; InKey
; entry : n/a
; * Get an input key
; exit : DX:AX = long value
; DX = shift states
; AH = scan code
; AL = char
; DS:DI => driver data
; Note : a null character state is returned as AX==0
cProc InKey,<PUBLIC,NEAR,ATOMIC>,<SI>
cBegin InKey
AssertEQ di,OFF_lpwDataKbd
mov bx,[di].pinkbCur
mov cx,[bx].fNormalKeyboardInkb
jcxz inkey_tsr
xor ax,ax
cCall LockRemoveQueue
mov dx,[di].ssCur
jnz end_inkey ; queue already locked
mov bx,[si].pHeadQueue
cmp bx,[si].pTailQueue
jne ik_readq
cCall FnzGetBiosKey
jnz ik_releaseq
xor ax,ax
jmp short ik_releaseq
ik_readq:
mov ax,[bx+0]
mov dx,[bx+2]
cCall IncQueuePtr
mov [si].pHeadQueue,bx
ik_releaseq:
cCall ReleaseRemoveQueue
end_inkey:
cEnd InKey
inkey_tsr:
xor bx,bx
mov ax,tsrcInkey ;* special get key request
int 16H ;* returns AH = sc, AL = char
;* BX = ss
mov dx,bx
jnz end_inkey ;* got one (dx always valid)
xor ax,ax
jmp short end_inkey
;----------------------------------------------------------------------------
;********** FnzGetBiosKey **********
;* entry : DS:DI => driver data
;* * check for a bios character
;* exit : z=> no key,
;* else AX = char + scan code, DX = shift states
;* TRASHES : AX/DX
cProc FnzGetBiosKey, <NEAR>
cBegin FnzGetBiosKey
AssertEQ di,OFF_lpwDataKbd
push bx ;* Some TSRs clobber this
push cx ;* possibly this too
mov ah,[di].Int16_CmdBase ; Is there anything to get?
inc ah
pushf
call [di].pfnOldInt16 ; call the real BIOS, not our hook
jz end_bios_get_key ; nope return z
; Liar! Check again!
mov ah,[di].Int16_CmdBase ; Burn some time; get kbd flags.
inc ah
inc ah
pushf
call [di].pfnOldInt16 ; call the real BIOS, not our hook
mov ah,[di].Int16_CmdBase ; Is there anything to get?
inc ah
pushf
call [di].pfnOldInt16 ; call the real BIOS, not our hook
jz end_bios_get_key ; nope return z
mov ah,[di].Int16_CmdBase ; Get char + scan code
pushf
call [di].pfnOldInt16
mov dx,[di].ssCur
or sp,sp ; set NZ flag, we got a key!
end_bios_get_key:
pop cx
pop bx
cEnd FnzGetBiosKey
;----------------------------------------------------------------------------
Int15Handler:
cmp ah,4Fh
jne @F
push ax
push bx
push cx
push si
push di
push ds
push es
mov di,SEG_lpwDataKbd
mov ds,di
mov di,OFF_lpwDataKbd ; DS:DI -> Data in data segment
mov si,[di].pinkbCur ; DS:SI -> INKB data
les bx,lpsslBios ; ES:BX -> kbd data in low ram
call ScanCodeStuff ; al = the scan code.
stc ; We don't want to eat the keystroke.
pop es
pop ds
pop di
pop si
pop cx
pop bx
pop ax
@@:
jmp [pfnOldInt15]
;----------------------------------------------------------------------------
;
; The keyboard hardware interrupt handler
Int09Handler:
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
mov di,SEG_lpwDataKbd
mov ds,di
mov di,OFF_lpwDataKbd ; DS:DI -> Data in data segment
mov si,[di].pinkbCur ; DS:SI -> INKB data
les bx,lpsslBios ; ES:BX -> kbd data in low ram
cmp [di].fInt15_4F_Supported,0
jne @F
in al,KbDataPort
cCall ScanCodeStuff ; Do the scan-code stuff.
@@: mov [di].fUnhook16, 1 ; Give normal int16 to TSRs
pushf
call [di].pfnOldInt09 ; Daisy chain.
mov [di].fUnhook16, 0
; Restore anything we did to the BiosShiftState in ScanCodeStuff.
test [di].fShiftStateDiddled,0ffH
jz @F ; Jmp if not diddled
mov al,[di].sslMirror
mov es:[bx],al
mov [di].fShiftStateDiddled,0
@@:
mov al,es:[bx]
mov [di].sslMirror,al
ifdef KANJI
mov ah, 51h ; AX bios: get KANA shift status
int 16h
and [di].ssCur, not SS_KANA
test ah, 00000010b ; test KANA bit
jz @F
or [di].ssCur, SS_KANA
@@:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -