📄 llcevt.asm
字号:
TITLE LLCEVT - Core GW-BASIC Event Interface
PAGE 56,132
;***
; LLCEVT - Core GW-BASIC Event Interface
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
; This module has the CORE EVENT support routines:
;
; 1. B$RDKYBD
; 2. B$KBDTRP....This is the keyboard interrupt handler. All keys
; are filtered through this interrupt routine.
; In case the key hit is not a trappable key
; it is allowed to pass through the ROM keyboard
; interrupt handler.
;
; The following is the relationship of several tables used in this
; module. TRTBL2, USRTBL2 & TRTBL4 are the table of flags, and
; TRTBL1 & USRTBL1 are the tables of definitions of keys (either
; the scan code or user's definitions). In order to support the
; IBM advanced 101-key keyboard (ronco keyboard), there are four
; entries paded after USRTBL2. This is for the convenience of
; table search for key number.
;
; The definition of the flag, please refer the comments for
; PPBEBL below.
;
; TRTBL2 -->|--| TRTBL1 -->|--| <-- Scan code of F1-F10
; |--| |--| (10 keys)
; (flags) ->|--| |--|
; \ \ \ \
; \ \ \ \
; |--| |--|
; |--| |--| <-- Scan code of cursor move key
; \ \ \ \ (4 keys)
; \ \ \ \
; USRTBL2 ->|--| USRTBL1 ->|--|--| <-- user key definition
; |--| |--|--| (11 keys)
; \ \ \ \ \
; \ \ \ \ \
; |--| |__|__|
; (dummy) ->|--|
; (0,4 keys)\ \ (no corresponding table)
; \ \
; TRTBL4 -->|--| (no corresponding table)
; |--|
; |__|
;
;******************************************************************************
INCLUDE switch.inc
INCLUDE rmacros.inc
useSeg _BSS
useSeg CONST
useSeg _DATA
useSeg EV_TEXT
INCLUDE seg.inc
INCLUDE ibmunv.inc
INCLUDE idmac.inc
INCLUDE intmac.inc
INCLUDE oscalls.inc
INCLUDE baslibma.inc
INCLUDE event.inc
INCLUDE const.inc
SUBTTL local constant definitions
page
;Number of keys
OrgFky = 10 ; normally, there is 10 function keys
CsrMovKy = 4 ; four cursor movement keys
ExtFky = 2 ; extended function keys (F11/F12)
;Scan codes
ScanPrtsc = 37H ; scan code for Prtsc
ScanPause = 45H ; scan code for Pause
ScanBreak = 46H ; scan code for Break
ScanF11 = 57H ; scan code for F11
ScanF12 = 58H ; scan code for F12
ScanExt1 = 0E0H ; scan code for extended keys
ScanExt2 = 0E1H ; scan code for extended keys
CTRLDown = 04H ; bit for CTRL been pressed
ALTDown = 08H ; bit for ALT been pressed
SUBTTL data definitions
page
sBegin _DATA
externB b$IOFLAG
externW b$IPOLKEY
externB b$CtrlFlags
staticB PPBEBL,07H ;This byte is used in the following way:
;Bit 0 used for CTRL BRK enable/disable
;Bit 1 used for CTRL PAUSE enb/disb
;Bit 2 used for CTRL PRTSC enb/disb
;ENABLE=1 and DISABLE=0
staticB TRTBL2,4,OrgFky+CsrMovKy; validate the first 14 keys (*)
staticB USRTBL2,0,NUM_UKEYS ; invalidate NUM_UKEYS user defined keys (*)
; Constants used in TRTBL2 and USRTBL2
TRP_OCCURED EQU 1 ; Bit 0 indicates occurence of a trap
TRP_ENABLED EQU 2 ; Bit 1 indicates trapping enb/disb
TRP_VALID EQU 4 ; Bit 2 indicates def valid/invalid
staticB ,0,NUM_GAP ; there is a gap between the last user
; defined key and F11
staticB TRTBL4,4,ExtFky ; flags for F11/F12, NOTE: TRTBL2, USRTBL2
; and TRTBL4 has to be contiguous and in
; this order
sEnd ;_DATA
sBegin CONST
staticB TRTBL1,<59,60,61,62,63>
staticB ,<64,65,66,67,68> ; 10 function keys
staticB ,<72,75,77,80> ; 4 cursor control keys
; currently, there is no need to use a
; table for F11/F12, since there are only
; two of them. Within the code, it checks
; the scan code of F11/F12 directly. But
; the trap flag table, TRTBL4, is needed.
staticB SHFTBL,<52H,3AH,45H,46H>; used to check for shift keys in SHKEYS
staticB ,<38H,1DH,2AH,36H> ; The last 3 entries must remain last!
sEnd ;CONST
sBegin _BSS
staticB WasE0E1,0 ; the value will be either 00H or 80H, to
; indicate the extended keys
externB b$NetCard ; defined in LLINI.ASM
; b$NetCard=1 --> network installed and
; running on 3.xx
; b$NetCard=0 --> network not installed
staticW USRTBL1,,NUM_UKEYS ; NUM_UKEYS user defined keys
staticW KEYHIT,,1
staticB LPTFLG,,1 ; line printer echo key flag
staticB POSFLG,,1 ; pause key flag
staticB BRKFLG,,1 ; break key flag
staticB KEYFLG,,1 ; trapped key flag
staticB KEYTRP,,1 ; key trapping enable/disable flag
staticB WASPOS,,1 ; helps in handling the CTRL PAUSE key.
; A value of 0 indicates that the CTRL
; PAUSE is not active, whereas a value
; of 0FFH indicates that the CTRL PAUSE
; is active. (used in B$KBDTRP & B$RDKYBD)
externB b$EventFlags ; misc event flags
sEnd ;_BSS
SUBTTL code externals
page
externFP B$IBreak ;interp call back to notify of CTRL-BREAK
sBegin EV_TEXT
assumes CS,EV_TEXT
externNP B$TrapEvent
externNP B$TestTrap
externNP B$ReqTrap
externNP B$Wakeup
externNP B$GETDS
SUBTTL B$RDKYBD - Keyboard control routine
PAGE
;***
;B$RDKYBD - Support for Keyboard Events
;OEM-interface routine
;
;Purpose:
; This routine allows the caller to do one of the following:
; (1) Check whether the key trap happened.
; (2) Define the user definable trap keys. The key definition syntax
; specifies a string.This string is passed directly to B$RDKYBD.
; (3) Start trapping keys.
; (4) Stop trapping keys.
; (5) Enable trapping for a specific key#
; (6) Disable trapping for specific key#
;
; See the documentation for B$POLLEV for a description of the
; event and trapping mechanisms.
;
; The string that is passed in as a parameter in function number
; 1 is directly from the user. It has to be checked for proper
; length and contents before it can be used. In this implementation,
; the length of this string must be 2. If the string is incorrect,
; return with PSW.C set and an ILLEGAL FUNCTION CALL will be
; generated.
;
;Entry:
; [AL] = 0: Return in [BX]
; 0 if no keyboard trap occurred
; key number if a trap key was detected
; -1 if ctrl-break was encountered
; -2 if pause was encountered
; -3 if LPTECHO was encountered
; 1: define a user definable key for trapping
; [BX] = address of the key definition string
; [CX] = length of the key definition string
; [DX] = key number
; 252: start trapping keys
; 253: stop trapping keys
; 254: enable trapping for key # [DX]
; Key number range is [-3,(max key index)]
; Key numbers are one relative, Key 0 not used.
; 255: disable trapping for key # [DX]
; Key number range is [-3,(max key index)]
; Key numbers are one relative, Key 0 not used.
; [BX] = value as specified by function [AL]
; [CX] = value as specified by function [AL]
; [DX] = value as specified by function [AL]
;
;Exit:
; [BX] = value, if specified by function [AL]
; [DX] = value, if specified by function [AL]
; PSW.C set will cause a function call error
;
;Uses:
; Per Convention
;
;Exceptions:
; None.
;******************************************************************************
;
;ALGORITHM:
;
; case [AL] of
; 0: begin
; if LPTFLG then
; begin
; set [BX] to -3
; clear LPTFLG
; end
; if (any trap key flag set ) then
; begin
; set [BX] to trap key #
; clear corr. trap key flag
; end
; else
; if POSFLG then
; begin
; set [BX] to -2
; clear POSFLG
; end
; else
; if BRKFLG then
; begin
; set [BX] to -1
; clear BRKFLG
; end
; else
; set [BX] to 0
; end
; 1: begin
; if (( [CX] < 1 ) or ( [CX] > 2 )) then
; set carry to indicate function
; call error
; else
; redefine key # [DX] using
; the address in [BX]
; end
; 252: enable
; 253: clear enable flag for all trappable keys
; 254: set enable flag for
; key # [DX]
; 255: clear enable flag for
; key # [DX]
; otherwise : set carry to indicate error
; in function call
; endcase
;
;DATA STRUCTURE:
; The trap table has NUM_TKEYS rows, each row made up of
; 2 bytes. The two bytes are required for the definition
; of a key string. There is another table having 20 rows
; each row having a byte. This byte is used to store
; three flags, namely
; 1. Definition valid or not
; 2. Key enabled or not
; 3. Trap occurred or not
; The mask is defined as follows:
; Bit 0 corresponds to the occurence of a key trap.
; Bit 1 corresponds to key Enable/Disable.
; Bit 2 corresponds to key definition validation.
;
;#****
cProc B$RDKYBD,<NEAR,PUBLIC>,ES
cBegin
PUSH DS
POP ES
CALL B$SetKybdInt ; install keyboard handler if not already
; installed
OR AL,AL ;test if key trapping status
JNZ RDK1A ;if not, then process normally
XOR BX,BX ;preset BX to zero
XCHG BL,KEYFLG ;swap zero and key trapping flag
OR BX,BX ;test if flag was set
RDK1A:
PUSH SI
push ax ; save [ax]
JZ RDKRET ; if flag was not set, then don't process it
ADD AL,4 ;[7] check if [AL] is within limits
JS RDKERR
CMP AL,6 ; no LOC/LOF support (one less entry)
JNB RDKERR
RDK2:
CBW ; since all positive, save one byte
SHL AX,1
MOV SI,AX ;[SI] = word index into table
PUSH ES
PUSH CX
PUSH DI
PUSH DS
POP ES ; make ES=DS
CALL CS:RDKOFST[SI]
POP DI
POP CX
POP ES
JMP SHORT RDKRET
RDKERR:
STC
RDKRET:
pop ax ; restore [ax]
POP SI
cEnd
RDKOFST DW TRPEBL
DW TRPDIS
DW ENABL
DW DISABL
DW KEYRTN
DW KEYDEF
SUBTTL B$SetKybdInt - Install keyboard handler
PAGE
;***
;B$SetKybdInt, B$InstKybdInt - install keyboard interrupt handler
;OEM-Interface Routine
;
;PURPOSE:
; These routines install the keyboard interrupt service
; routine. B$SetKybdInt checks to see if the routine has already
; been installed and returns without doing anything if it has
; been. B$InstKybdInt does not check if there is already a keyboard
; servrice routine.
;
;Preserves:
; AX
;
;********************************************************************
cProc B$SetKybdInt,<NEAR,PUBLIC>
cBegin
TEST b$EventFlags,KybdInst ; keyboard service routine installed ?
JZ B$InstKybdInt ; brif not -- install it
RET ; otherwise, just return
labelNP <B$InstKybdInt>
CLI ;clear interrupts
PUSH DS
PUSH DX
PUSH AX
PUSH CS
POP DS ;[DS] := [CS]
SETVEC KYBINT,B$KBDTRP ;install new keyboard service routine
POP AX
POP DX
POP DS
OR b$EventFlags,KybdInst ; set init flag
STI ;restore interrupts
cEnd
;**
;This routine returns the key that was most
;recently struck. Actually it returns a value
;in [BX] corresponding to the key struck.
KEYRTN:
CMP LPTFLG,1 ;was it the line printer echo?
JNE TRPKYS ;no, check for the trap keys
MOV LPTFLG,0 ;clear the printer echo flag
MOV BX,-3 ;return a -3 in BX
JMP SHORT KEYRET
TRPKYS:
MOV DI,OFFSET DGROUP:TRTBL2 ;[DI] = offset of trap table 2
MOV CX,NUM_TKEYS ; [CX] = count of total function keys
; including the gap (which is always 0)
; this number including the 4 padding
; entries
MOV AL,07H ;[AL] = 00000111B
CLD ;just to be safe
REPNZ SCASB ;search for a trapped key
JNZ POSBRK ; Brif none found, the original code used
; count=(total number of keys)+1 and JCXZ
; here, it was OK. I use JNZ and count=
; (total number of keys) instead. The
; effect is waste one byte, but save one
; comparison.
SUB CX,NUM_TKEYS ; getting the 1-relative key
NEG CX ;number in [CX]
DEC DI ;adjust [DI] to point to found key
AND BYTE PTR[DI],0FEH ;clear the trap flag for this key
MOV BX,CX ;return the key number in [BX]
JMP SHORT KEYRET
POSBRK:
CMP POSFLG,1 ;was it the pause key?
JNE CHKBRK ;no, check for BRK
MOV POSFLG,0 ;yes, clear the pause key flag
MOV BX,-2 ;return -2 in BX
NOT WASPOS ;WASPOS indicates whether
;CTRL PAUSE is active or not
JMP SHORT KEYRET
CHKBRK:
CMP BRKFLG,1 ;was it the break key
JNE NOKEYS ;no, jump to no keys trapped
MOV BRKFLG,0 ;clear the break flag
MOV BX,-1 ;return -1 in BX
JMP SHORT KEYRET
NOKEYS:
XOR BX,BX ; return 0 to indicate no keys
; and XOR clear the carry flag
RET ; return with NC & BX=0
KEYRET:
MOV KEYFLG,1 ;set flag to process again
CLC ;indicate no error
RET
;**
;This routine is used to define a user defined
;trap key.
; DI is used. (caller, B$RDKYBD preserves AX,CX,SI,DI)
; BX is preserved.
KEYDEF:
CMP CX,2 ;is CX = 2 as it should be
STC ; assume error
JNE DEFRET ; Brif CX <> 2, return with CY (error)
PUSH BX ; save BX
MOV CX,[BX] ;get the key definition in [CX]
XCHG CH,CL ;swap before storing
TEST CH,3 ; left/right shift been pressed ?
JZ NO_SHIFT ; Brif not
OR CH,3 ; make both the same
NO_SHIFT:
MOV DI,DX ; # in DI
SUB DI,OrgFky+CsrMovKy+1 ; map 15,16,... to 0,1,...
MOV BX,OFFSET DGROUP:USRTBL2; [BX] = offset of trap table 2
OR BYTE PTR [BX+DI],TRP_VALID ; validate the new definition
MOV BX,OFFSET DGROUP:USRTBL1; [BX] = offset of trap table 1
SHL DI,1 ; get the word offset
MOV WORD PTR[BX+DI],CX ; store the new key definition
POP BX ; get back BX
CLC
DEFRET:
RET
;**
;enables key trapping
TRPEBL:
MOV KEYTRP,1
CLC ; original code exit via TRPDIS, slower
RET
;**
;disables key trapping
TRPDIS:
MOV KEYTRP,0
CLC
RET
;**
;enables trapping for key # [DX]
ENABL:
PUSH DX ;save [DX]
OR DX,DX ; is [DX]>0 ? NOTE: [DX]=0 isn't taken care
JG ENABL1 ;Brif so
NEG DX ;else complement [DX]
CMP DL,3 ;if [DL]=3 then [DL]:=4
JB ENABL0 ;Brif not
INC DL ;else make [DL]=4
ENABL0:
OR PPBEBL,DL ;enable the corresponding key
; carry is cleared
JMP SHORT ENABL2
ENABL1:
MOV DI,OFFSET DGROUP:TRTBL2-1 ; [DI] = (offset of trap table2)-1
ADD DI,DX ;get byte offset in table
OR BYTE PTR[DI],02H ;enable the key
; carry is cleared
ENABL2:
POP DX ;restore [DX]
RET ; with NC
;**
;disables trapping for key # [DX]
DISABL:
PUSH DX ;save [DX]
OR DX,DX ; is [DX]>0 ? NOTE: [DX]=0 isn't taken care
JG DISBL1 ;Brif so
DEC DX ;disable the corresponding key
;Bug fixed April 12,1984
CMP DL,0FCH ;is low nibble of [DL]=1100 ?
JA DISBL0 ;Brif not
DEC DL ;else make it 1011
DISBL0:
AND PPBEBL,DL ;leaving the others intact
; carry is cleared
JMP SHORT DISBL2
DISBL1:
MOV DI,OFFSET DGROUP:TRTBL2-1 ; [DI] = (offset of trap table2)-1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -