home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
extra
/
nyenhuis2.arc
/
MSUHP1.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-07-01
|
52KB
|
1,434 lines
NAME msuhp1
; File MSUHP1.ASM
; Keyboard translator, by Joe R. Doupnik, Dec 1986
; with contributions from David L. Knoell.
; For HP 150 Kermit (DOS level i/o)
; edit history:
; Last edit 4 June 1988
; 1 July 1988 Version 2.31
; 4 June 1988 Add changes at dfkey1e, dfkey12, add test to read from files
; 2 Jan 1988 version 2.30
include mssdef.h
public keybd, dfkey, shkey, msuinit
; some definitions
maxkeys equ 128 ; maximum number of key definitions
maxstng equ 64 ; maximum number of multi-char strings
stbuflen equ 1000 ; length of string buffer (bytes)
verb equ 8000h ; dirlist flag: use verb action table
strng equ 4000h ; dirlist flag: use string action table
scan equ 100h ; keycode flag: code is scan not ascii
braceop equ 7bh ; opening curly brace
bracecl equ 7dh ; closing curly brace
datas segment public 'datas'
extrn taklev:byte, comand:byte, intake:byte, flags:byte
extrn shkadr:word, stkadr:word, trans:byte
; system dependent references
;;; System Independent local storage
tranbuf db 132 dup (?) ; 132 byte translator work buffer
crlf db cr,lf,'$'
dfhelp1 db cr,lf,' Enter key',27h,'s identification as a character',cr,lf
db ' or as its numerical equivalent \{b##} of ascii',cr,lf
db ' or as its scan code \{b##}'
db cr,lf,' or as SCAN followed by its scan code',cr,lf
db ' where b is O for octal, X for hex, or D for decimal'
db ' (default).',cr,lf,' Braces {} are optional.'
db cr,lf,' Follow the identification with the new definition.'
db cr,lf,' or CLEAR to restore initial key settings.$'
dfaskky db cr,lf,' Push key to be defined: $'
dfaskdf db cr,lf,' Enter new definition: $'
verbbad db cr,lf,' No such verb',cr,lf,'$'
strbad db cr,lf,' Not enough space for new string',cr,lf,'$'
keyfull db cr,lf,' No more space to define keys',cr,lf,'$'
dfkopps db cr,lf,' Opps! That is Kermit',27h,'s Escape Char.'
db ' Translation is not permitted.',cr,lf,'$'
shkmsg1 db cr,lf,'Push key to be shown (? shows all): $'
shkmsg2 db ' decimal is defined as',cr,lf,'$'
shkmsg3 db cr,lf,'... more, push any key to continue ...$'
kwarnmsg db cr,lf,' Notice: this form of Set Key is obsolete$'
ascmsg db ' Ascii char: $'
scanmsg db ' Scan Code $'
strngmsg db ' String: $'
verbmsg db ' Verb: $'
noxmsg db ' Self, no translation.$'
fremsg db cr,lf,' Free space: $'
kyfrdef db ' key and $'
stfrdef db ' string definitions, $'
stfrspc db ' string characters.',cr,lf,'$'
; translation tables
keylist dw maxkeys dup (?) ; 16 bit keycodes, paralled by dirlist
dirlist dw maxkeys dup (?) ; director {v+s} + {index | new char}
sptable dw maxstng dup (?) ; list of asciiz string offsets
stbuf dw stbuflen dup (?) ; buffer for strings
strmax dw stbuf ; first free byte in stbuf
listptr dw ? ; item number for keylist and dirlist
nkeys dw ? ; number of actively defined keys
keycode dw ? ; ascii/scan code for key
kbtemp dw ? ; scratch storage for translator
brace db ? ; brace detected flag byte
oldform db ? ; old form Set Key, if non-zero
verblen dw ? ; length of user's verb (work temp)
kwcnt dw ? ; number of keywords (work temp)
msutake db ? ; if being run from take file or not
twelve dw 12d
dosflg db 0
;;; End System Independent Data Area
;;; System Dependent Data Area
; edit dfhelp2 to include nice list of verbs for this system.
dfhelp2 db cr,lf,' Enter either \{Kverb} for a Kermit action verb',cr,lf
db ' or a replacement string (single byte binary numbers are'
db ' \{b##})',cr,lf,' or nothing at all to undefine a key.'
db cr,lf,' Braces {} are optional, and strings maybe enclosed in'
db ' them.',cr,lf,' Strings may not begin with the character'
db ' combinations of \k or \{k',cr,lf
db ' (start with a { brace instead).',cr,lf,lf
db ' Verbs are as follows:',cr,lf
db ' break, help, prtscn, status, exit'
db cr,lf,'$'
; Aliaskey: keys having aliases - same ascii code but more than one
; scan code, as on auxillary keypads. Use just scan codes with these.
; Alternative use: force ascii keys to report out just scan codes.
; Table format: high byte = scan code, low byte = ascii code.
; Contents are machine dependent.
aliaskey db 0
aliaslen equ ($-aliaskey) shr 1 ; number of words in aliaskey table
kverbs db 5 ; number of table entries below
mkeyw 'prtscn',trnprs ; independent of ordering and case!
mkeyw 'break',sendbr ; mkeyw 'name',procedure entry point
mkeyw 'help',cquery
mkeyw 'status',cstatus
mkeyw 'exit',cquit
; Initialization data.
kbdinlst equ this byte ; Kermit IBM initialization time keyboard setup
dw 0 ; end of table marker
datas ends
; Documentation
;Translating a key:
; The translator is called to obtain keyboard input; it sends characters to
; the serial port through standard controlled echo procedures or invokes
; named procedures. It returns carry clear when its operation is completed
; for normal actions and carry set when Connect mode must be exited. When
; Connect mode is exited the just read char should be passed in Kbdflg
; to msster.asm for invoking actions such as Status, send a break,
; quit connect mode; system dependent procedure Term is responsible for this.
;
; Principal procedures are -
; msuinit Initializes keyboard translator in this file when
; Kermit first begins. Installs dfkey and shkey as the
; procedures used for Set Key and Show Key. Sys Indep.
; Called from msx or msy init procs. System Independent.
; keybd Performs the translation, outputs chars to the serial
; port or invokes a Kermit action routine. Sys Indep.
; dfkey Defines a key's translation. Reads command line
; via Kermit's command parser comnd. System Independent.
; shkey Shows translation of a key. Requests user to push
; selected key. System Independent.
;
; kbdinit optional. Initializes the translation tables when
; Kermit starts up. Called by msuinit. System Dependent.
; getkey Performs the keyboard read and returns results in
; a standardized system independent format. Sys Depend.
; postkey called by active translator after obtaining a keycode.
; Used to provide extra local actions (keyclick) only
; in Connect mode (not during Set/Show key commands).
; Called by keybd. System dependent.
; Supporting system independent procedures are -
; shkfre (show string free space), tstkeyw (finds user's keyword in the verb
; table), insertst (insert string in buffer), remstr (delete string in buffer).
;
; System dependent procedure Getkey reads a keycode (usually via a Bios
; call). On IBM compatible machines this yields <ah=scan code, al=ascii>
; for ordinary keys, or <ah=scan code, al=0> for special keys such as F1,
; or <ah=0, al=###> when Alt### is used.
; For any system, the canonical output form is the key's code in Keycode.
; Place the ascii code (or scan code if none) in byte Keycode and ancillary
; info (shift states plus marker bit for scan codes) in byte Keycode + 1.
;
; Table Aliaskey is a list of scan code/ascii codes for keys which appear
; more than once on a keyboard. This list is examined to distinguish such
; aliased keys (those on an auxillary keypad) from an ordinary ascii key,
; and the aliased key is then referenced by its scan code rather than by
; the ordinary ascii code. Aliaskey is machine and keyboard dependent.
;
; Procedure Keybd calls Getkey for the Keycode, checks list of translatable
; keys Keylist, and then either sends an ascii string (one or more characters)
; or invokes a Kermit action verb. List Dirlist indicates what kind of
; translation to do. Keybd is system independent but may contain system
; dependent special actions such as echoing keyclicks. Keybd calls system
; dependent procedure Postkey just after calling getkey so local actions
; such as keyclicks can be activated only during Connect mode operations.
;
; Keylist is a packed but unordered list of 16 bit keycodes which need
; translation. The lower order byte holds a key code (ascii char or scan code)
; while the high byte holds a scan code marker bit (0 if ascii code in low
; byte) plus any ancillary keyboard information such as Control/Shift/Alt/Meta
; keys being held down; these are of use in Show Key presentations.
; Dirlist parallels Keylist to provide the kind of translation, verb or
; string, in the two highest bits with the other bits holding either
; a single new replacement character or the item number in lists of verbs
; or strings. If neither verb nor strng type bits are set in a dirlist
; word then the translation is a single new character held in the lower
; eight bits of that dirlist word.
;
; The number of key translations is assembly constant Maxkeys (def 128).
; The maximum number of strings is assembly constant Maxstngs (def 64).
; The maximum number of verbs is 256 and is set by building table Kverbs.
;
; For verbs, use the Item number from the Director table Dirlist to select
; a procedure offset from the structured list Kverbs and jump to that offset.
; Most verb procedures return carry clear to stay within Connect mode.
; Verbs requiring exiting Connect mode return carry set and may set byte
; Kbdflg to a char code which will be read by msster.asm for activating a
; transient Kermit action such as send a break (Kbdflg = 'b').
; Kbdflg is stored in msster.asm (as zero initially, meaning ignore it).
; Action verb procedures are normally located in a system dependent file.
;
; For multi-char strings, use Item number from Director table Dirlist to
; select a pointer to a string. The list of string pointers is Sptable
; (string pointer table) which holds the offset in the data segment of the
; strings stored in buffer Stbuf. In stbuf strings are held as: one byte of
; length of following text and then the text itself (permits embedded nulls).
; Use Chrout to send each string character, and finally return from Keybd
; with carry clear.
;
; For single character replacements obtain the new character from the lower
; order byte of Director table Dirlist. If the character is Kermit's present
; escape character return from Keybd carry set to leave connect mode.
; Otherwise, send the character via Chrout and return from Keybd carry clear.
; Keylist table format:
; 7 bits 1 bit 8 bits
; +----------+----+------------+ scan bit = 1 if key's code is non-ascii
; | aux info |scan| key's code | aux info = system dependent, used only to
; +----------+----+------------+ help identify key
;
; Dirlist table format v s meaning
; 1 1 14 bits 0 0 copy out one byte translation
; +---+---+--------------------+ 1 0 copy out multi-char string number Item
; | v | s | item # or new char | 0 1 do action verb number Item
; +---+---+--------------------+ 1 1 (not used)
;
; Table kverbs is organized by macro mkeyw as -
; kverbs db number of table entries
; (each entry is in the form below:)
; db number of bytes in verbname
; db 'verbname' variable length
; db '$' for printing
; dw value offset of procedure
;
;
; Dfkey defines a key to be itself (undefines it) or a single replacement
; character or a character string or a Kermit action verb. Dfkey requires
; a command line so that it may be invoked by Take files but can be forced
; to prompt an interactive user to push a key. Syntax is discussed below.
; Note that redefined keys have their old definitions cleared so that
; old string space is reclaimed automatically.
;
; Shkey displays a key's definition and the user is asked to push the
; selected key. The free space for strings is always shown afterward. See
; below for syntax.
;
; Kbdinit is an optional routine called when Kermit starts up. It fills in
; the translation tables with desirable default values to save having to
; use long mskermit.ini files. The default values are stored in a structured
; table similar to (but not the same as) Dfkey's command lines; the keycode
; values are preset by hand to 16 bit numbers.
;Defining a key:
; Command is SET KEY <key ident><whitespace><definition>
;
; <key ident> is
; a single ordinary ascii char or
; the numerical equivalent of an ascii char or
; a Scan Code written as a number or
; keyword SCAN followed by a number.
; ? Displays help message.
; Numbers and Binary codes are of the form
; \123 a decimal number
; \o456 an octal number base letters o, d, x can be
; \d213 a decimal number upper or lower case
; \x0d a hex number
; \{b###} braces around above material following slash.
;
; <whitespace> is one or more spaces and or tabs.
;
; <definition> is
; missing altogether which "undefines" a key.
; \Kverb for a Kermit action verb; upper or lower case K is ok
; \{Kverb} ditto. Verb is the name of an action verb.
; text a string with allowed embedded whitespace and embedded
; binary chars as above. This kind of string may not
; commence with sequences \K or \{K; use braces below.
; {text} string confined to material within but excluding
; the braces. Note, where the number of opening braces
; exceeds the number of closing braces the end of line
; terminates the string: {ab{}{{c}d ==> ab{}{{c}d
; but {ab}{{c}d ==> ab.
; ? Displays help message and lists all action verbs.
;
; If Set Key is given interactively, as opposed to within a Take
; file, the system will prompt for inputs if none is on the command
; line. The response to Push key to be defined cannot be edited.
;
; Text which reduces to a single replacement character is put into a
; table separate from the multi-character strings (maxstng of these).
; A key may be translated into any single 8 bit code.
;
; Comments can follow a Kermit action verb or a braced string; no
; semicolon is required since all are stripped out by the Take file
; reader before the defining text is seen by SET KEY.
;
; The current Kermit escape character cannot be translated without
; subtrafuge.
;
; Examples:
; Set Key q z
; makes key q send character z
; Set Key \7 \27[0m
; makes key Control G send the four byte
; string ESC [ 0 m
; Set Key q
; undefines key q so it sends itself (q) again.
; Set Key \2349 \kexit
; defines IBM Alt-X to invoke the leave connect
; mode verb "exit" (Kermit's escape-char ^] C).
; Set Key \x0c Login \{x0d}myname\{x0d}mypass\x0d
; defines Control L to send the string
; Login <cr>myname<cr>mypass<cr>
;
; Alternative Set Key syntax for backward compatibility with previous versions
; The same forms as above except the key identification number must
; be decimal and must Not have a leading backslash. Example:
; Set Key Scan 59 This is the F1 key
;
; If the definition is omitted it may be placed on the following line;
; if that line is also empty the key is undefined (defined as Self).
; A warning message about obsolete syntax will be given followed by
; the key's modern numerical value and new definition. Only "special"
; keys (those not producing ascii codes) are compatible with this
; translator.
;
;Showing a key:
; Command is SHOW KEY <cr>
; System prompts user to press a key and shows the definition plus the
; free space for strings. Query response results in showing all definitions.
; End Documentation
code segment public 'code'
; system independent external items
extrn comnd:near, prompt:near, iseof:near ; in msscmd
extrn isfile:near, strlen:near ; in mssfil
extrn cnvlin:near, katoi:near, decout:near ; in mssset
; system dependent external items
; these are system dependent action verbs, in msxhp1
extrn beep:near, trnprs:near, sendbr:near
extrn chrout:near, cstatus:near, cquit:near, cquery:near
assume cs:code, ds:datas, es:datas
; Begin system independent Keyboard Translator code
; MSUINIT performs Kermit startup initialization for this file.
; Note, shkadr and stkadr are pointers tested by Set/Show Key calls. If they
; are not initialized here then the older Set/Show Key procedures are called.
MSUINIT PROC NEAR ; call from msx/msy init code
call kbdinit ; optional: init translator tables
mov shkadr,offset shkey ; declare keyboard translator present
mov stkadr,offset dfkey ; via Show and Set Key proc addresses
ret
MSUINIT ENDP
; Call Keybd to read a keyboard char (just returns carry clear if none) and
; 1) send the replacement string (or original char if not translated)
; out the serial port, or
; 2) execute a Kermit action verb.
; Returns carry set if Connect mode is to be exited, else carry clear.
; Modifies registers ax and bx.
KEYBD PROC NEAR ; active translator
call getkey ; read keyboard
jnc keybd1 ; nc = data available
jmp keybdx ; else just return carry clear
keybd1: call postkey ; call system dependent post processor
cmp nkeys,0 ; is number of keys defined = 0?
jz keybd3 ; z = none defined
push di ; search keylist for this keycode
push cx ; save some registers
push es
mov di,offset keylist ; list of defined keycode words
mov ax,keycode ; present keycode
mov cx,nkeys ; number of words to examine
push ds
pop es ; make es:di point to datas segment
cld
repne scasw ; find keycode in list
pop es ; restore regs
pop cx
je keybd1b ; e = found, work with present di
pop di ; restore original di
test keycode,scan ; is this a scan code?
jz keybd3 ; z = no, it's ascii, use al as char
call beep ; say key is a dead one
clc
ret ; and exit with no action
keybd1b:sub di,2 ; correct for auto increment
sub di,offset keylist ; subtract start of list ==> listptr
mov ax,dirlist[di] ; ax = contents of director word
pop di ; restore original di
; dispatch on Director code
test ax,verb ; verb only?
jnz keyvb ; e = yes
test ax,strng ; multi-char string only?
jnz keyst ; e = yes, else single char & no xlat
;
; do single CHAR output (char in al)
keybd3: cmp al,trans.escchr ; Kermit's escape char?
je keybd3a ; e = yes, handle separately
call chrout ; transmit the char
clc ; return success
ret
keybd3a:stc ; set carry for jump to Quit
ret
keyvb: and ax,not(verb+strng) ; VERB (ax=index, remove type bits)
mov bx,offset kverbs ; start of verb table
cmp al,byte ptr [bx] ; index > number of entries?
jae keybdx ; ae = illegal, indices start at 0
inc bx ; bx points to first entry
push cx ; save reg
mov cx,ax ; save the index in cx
inc cx ; counter, indices start at 0
keyvb1: mov al,byte ptr [bx] ; cnt value
xor ah,ah
add ax,4 ; skip text and '?' and value word
add bx,ax ; look at next slot
loop keyvb1 ; walk to correct slot
sub bx,2 ; backup to value field
keyvb2: pop cx ; restore reg
mov bx,[bx] ; get value field of this slot
cmp bx,0 ; jump address defined?
je keybdx ; e = no, skip the action
jmp bx ; perform the function
keyst: and ax,not(verb+strng) ; STRING (ax=index, remove type bits)
shl ax,1 ; convert to word index
push si ; save working reg
mov si,ax ; word subscript in table
mov si,sptable[si] ; memory offset of selected string
cmp si,0 ; is there a string pointer present?
je keyst3 ; e = no, skip operation
cld ; scan forward
lodsb ; get string length byte
mov cl,al
xor ch,ch ; to cx for looping
jcxz keybdx ; z = null length
keyst2: lodsb ; get new string char into al
push si ; save si and cx around call
push cx
call chrout ; send out the char in al
pop cx ; recover regs
pop si
loop keyst2 ; loop through whole string
keyst3: pop si ; restore reg
keybdx: clc ; return success
ret
KEYBD ENDP
; SET KEY - define a key (procedure dfkey)
; SET KEY <key ident><whitespace><new meaning>
; Call from Kermit level. Returns as ret if failure or as rskp if success.
;
DFKEY PROC NEAR ; define a key as a verb or a string
mov keycode,0 ; clear keycode
mov oldform,0 ; say no old form Set Key yet
mov dx,offset tranbuf ; our work space
mov word ptr tranbuf,0 ; insert terminator
mov bx,offset dfhelp1 ; first help message
mov ah,cmfile ; parse a word
call comnd ; get key code or original ascii char
nop
nop
nop
mov al,intake ; reading from Take file indirectly
or al,taklev ; ditto, directly
mov msutake,al ; save here
or ah,ah ; any text given?
jnz dfkey12 ; nz = yes, so don't consider prompts
; interactive key request
cmp intake,0 ; in a Take file?
je dfkey10 ; e = no, prompt for keystroke
jmp dfkey0 ; else say bad syntax
dfkey10:mov ah,prstr
mov dx,offset dfaskky ; ask for key to be pressed
int dos
dfkey11:call getkey ; read key ident from keyboard
jc dfkey11 ; c = no response, wait for keystroke
mov ah,prstr ; display cr/lf
mov dx,offset crlf
int dos
call shkey0 ; show current definition (in SHKEY)
jmp dfkey1e ; prompt for and process definition
dfkey12: ; Look for word SCAN and ignore it
mov dx,word ptr tranbuf ; get first two characters
or dx,2020h ; map upper to lower case
cmp dx,'cs' ; first two letters of word "scan"?
je dfkey ; e = yes, skip the word
cmp dx,'lc' ; first two letters of word "clear"?
je dfkey15 ; e = yes, reinit keyboard [2.31]
cmp dx,'fo' ; first two letters of "off"
je dfkey13 ; e = yes, use DOS keyboard calls
cmp dx,'no' ; first two letters of "on"
je dfkey14 ; e = yes, use standard kbd calls
cmp ah,1 ; number of characters received
ja dfkey1 ; a = more than one, decode
mov ah,byte ptr tranbuf ; get the single char
mov byte ptr keycode,ah ; store as ascii keycode
jmp dfkey1b ; go get definition
dfkey13:mov dosflg,0ffh ; set DOS keyboard read flag
jmp short dfkey14a
dfkey14:mov dosflg,0 ; clear DOS keyboard read flag
dfkey14a:mov ah,cmcfm ; added after version 2.30
call comnd
jmp r
nop
jmp rskp
dfkey15:mov ah,cmcfm ; added after version 2.30
call comnd ; confirm request before proceeding
jmp r
nop
jmp short dfkeyc ; execute command
dfkey0: mov dx,offset dfhelp1 ; say bad definition command
mov ah,prstr
int dos
jmp rskp
dfkeyc: ; CLEAR key defs, restore startup defs
mov cx,maxkeys ; size of keycode tables
push es ; save register
push ds
pop es ; make es point to datas segment
mov ax,0 ; null, value to be stored
mov di,offset dirlist ; director table
cld
rep stosw ; clear it
mov cx,maxkeys
mov di,offset keylist ; keycode table
rep stosw ; clear it
pop es ; recover register
mov strmax,offset stbuf ; clear string buffer
mov stbuf,0 ;
mov bx,offset sptable
mov word ptr [bx],0 ; clear table of string pointers
mov nkeys,0 ; clear number of defined keys
call msuinit ; restore startup definitions
jmp rskp
; Multi-char key identification
dfkey1: mov si,offset tranbuf ; point to key ident text
cmp byte ptr [si],'0' ; is first character numeric?
jb dfkey1a ; b = no
cmp byte ptr [si],'9' ; in numbers?
ja dfkey1a ; a = no
mov keycode,scan ; setup keycode for scan value
mov dx,si ; get length of string in cx
call strlen
push ds
pop es ; make es point to datas segment
push si
add si,cx ; point at string terminator
mov di,si
inc di ; place to store string (1 byte later)
inc cx ; include null terminator
std ; work backward
rep movsb ; move string one place later
cld
pop si
mov byte ptr [si],'\' ; make ascii digits into \nnn form
mov oldform,0ffh ; set old form flag
mov dx,offset kwarnmsg ; tell user this is old form
mov ah,prstr
int dos
dfkey1a:call katoi ; convert ascii number to binary in ax
jc dfkey0 ; c = no number converted
or keycode,ax ; store in keycode
dfkey1b: ; Get Definition proper
test oldform,0ffh ; old form Set Key active?
jz dfkey1f ; z = no
mov bx,offset tranbuf ; get new definition on main cmd line
mov word ptr [bx],0 ; insert terminator
mov dx,offset dfhelp2 ; help for definition of key
mov ah,cmtxt ; read rest of line into tranbuf
call comnd
nop ; allow null definitions
nop
nop
or ah,ah ; char count zero?
jz dfkey1e ; z = zero, prompt for definition
jmp dfkey1g ; process definition
dfkey1e:mov ah,prstr
mov dx,offset crlf
int dos
mov dx,offset dfaskdf ; prompt for definition string
call prompt ; Kermit prompt routine
mov comand.cmwhite,1 ; allow leading whitespace
mov comand.cmcr,1 ; permit bare carriage returns
dfkey1f:mov bx,offset tranbuf ; get new definition
mov word ptr [bx],0 ; insert terminator
mov dx,offset dfhelp2 ; help for definition of key
mov ah,cmtxt ; read rest of line into tranbuf
call comnd
jmp r ; exit now on ^C from user
nop
mov comand.cmcr,0 ; turn off allowance for bare c/r's
dfkey1g:xchg ah,al ; put byte count in al
xor ah,ah ; clear high byte
mov kbtemp,ax ; and save count in kbtemp
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; none so declare parse error
nop ; round out to three bytes
mov cx,kbtemp ; string length
jcxz dfkey2 ; z = empty string
push si
push di
mov si,offset tranbuf ; strip leading white space
dfkey1c:cld ; work forward
lodsb ; read string char into al
dec cx ; number of chars left to read
cmp al,' ' ; a space?
je dfkey1c ; e = yes, keep going
cmp al,tab ; tab?
je dfkey1c ; e = yes, keep going
dec si ; offset inc si in lodsb
add cx,2 ; include terminator, offset dec above
jcxz dfkey1d ; z = nothing to move
mov di,offset tranbuf ; destination is start of buffer
push ds
pop es
cld
rep movsb ; copy text part of string
dfkey1d:pop di
pop si
dfkey2: ; Examine translation
mov al,trans.escchr ; current escape char (port dependent)
cmp al,byte ptr keycode ; is this Kermit's escape char?
jne dfkey2a ; ne = no
test keycode,scan ; see if scan code
jnz dfkey2a ; nz = scan, so not ascii esc char
mov dx,offset dfkopps ; Opps! msg
mov ah,prstr ; complain and don't redefine
int dos
jmp rskp
dfkey2a:push di ; get a director code for this key
push cx
mov di,offset keylist ; list of keycodes
mov cx,nkeys ; number currently defined
mov ax,keycode ; present keycode
jcxz dfkey2b ; cx = 0 means none defined yet
cld
push ds
pop es
repne scasw ; is current keycode in the list?
jne dfkey2b ; ne = not in list
sub di,2 ; correct for auto increment
sub di,offset keylist
mov listptr,di ; list pointer for existing definition
pop cx
pop di
jmp dfkey3 ; go process definition
dfkey2b:pop cx ; key not currently defined so
pop di ; make a new director entry for it
mov bx,nkeys ; number of keys previously defined
cmp bx,maxkeys ; enough space?
jae dfkey2c ; ae = no, complain
shl bx,1 ; count words
mov listptr,bx ; index into word list
mov ax,keycode ; get key's code
mov keylist[bx],ax ; store it in list of keycodes
mov dirlist[bx],0 ; clear the new director entry
inc nkeys ; new number of keys
jmp dfkey3 ; go process definition
dfkey2c:mov dx,offset keyfull ; say key space is full already
mov ah,prstr
int dos
jmp rskp ; tell parser we are happy
; listptr has element number in keylist or dirlist; keycode has key's code.
; Parse new definition. First look for Kermit verbs as a line beginning
; as \K or \{K. Otherwise, consider the line to be a string.
; In any case, update the Director table for the new definition.
dfkey3: mov brace,0 ; assume not using braces
mov si,offset tranbuf ; start of definition text
cmp byte ptr [si],'\' ; starts with escape char?
jne dfkey5 ; ne = no, so we have a string
inc si ; skip the backslash
cmp byte ptr [si],braceop ; starts with \{?
jne dfkey3a ; ne = no
inc si ; skip the opening brace
mov brace,bracecl ; expect closing brace
dfkey3a:cmp byte ptr [si],'K' ; starts with \{K or \K?
je dfkey3b ; e = yes
cmp byte ptr [si],'k' ; starts as \{k or \k?
jne dfkey5 ; ne = no, then it's a string
dfkey3b:inc si ; yes, skip the K too
; Kermit action VERBS
push si ; save verb name start address
dfkey4a:cld
lodsb ; scan til closing brace or w/s or end
cmp al,0 ; premature end?
je dfkey4b ; e = yes, accept without brace
cmp al,brace ; closing brace?
je dfkey4b ; e = yes
cmp al,spc ; white space or control char?
ja short dfkey4a ; a = no, so not at end yet
dfkey4b:mov byte ptr[si-1],0 ; insert null terminator
pop si ; recover start address
call tstkeyw ; find keyword, kw # returned in kbtemp
jc dfkey4d ; c = no keyword found, complain
call remstr ; clear old string, if string
mov ax,kbtemp ; save keyword number
and ax,not(verb+strng) ; clear verb / string field
or ax,verb ; set verb ident
mov si,listptr
mov dirlist[si],ax ; store info in Director table
jmp dfkey7 ; show results and return success
dfkey4d:mov dx,offset verbbad ; say no such verb
mov ah,prstr
int dos
jmp rskp
; Here we are left with the definition string; si points to its start, and
; kbtemp holds its length (number of bytes). Null termination. If the string
; begins with an opening brace it terminates on a matching closing brace
; or the end of line, whichever occurs first.
; Null length strings mean define key as Self.
; STRING definitions
dfkey5: mov si,offset tranbuf ; start of string text
cmp byte ptr [si],braceop ; opening brace?
jne dfkey5f ; ne = no, ignore brace-matching code
mov dl,braceop ; opening brace (we count them up)
mov dh,bracecl ; closing brace (we count them down)
mov kbtemp,0 ; we are at brace level 0
dfkey5b:cld ; search forward
lodsb ; read a string char
cmp al,0 ; at end of string?
je dfkey5d ; e = yes, we are done
cmp al,dl ; an opening brace?
jne dfkey5c ; ne = no
inc kbtemp ; yes, increment brace level
jmp short dfkey5b ; and continue scanning
dfkey5c:cmp al,dh ; closing brace?
jne dfkey5b ; ne = no, continue scanning
dec kbtemp ; yes, decrement brace level
cmp kbtemp,0 ; at level 0?
jne dfkey5b ; ne = no, #opening > #closing braces
mov byte ptr [si-1],0 ; plant terminator on closing brace
dfkey5d:mov si,offset tranbuf+1 ; skip opening brace
dfkey5f:call remstr ; first, clear old string, if any
mov di,offset tranbuf ; si=source, di=dest, convert in-place
call cnvlin ; convert numbers, cx gets line length
mov si,offset tranbuf ; provide address of new string
cmp cx,1 ; just zero or one byte to do?
jbe dfkey6 ; e = yes, do as a char
call insertst ; insert new string, returns reg cx
jc dfkey5h ; c = could not do insert
mov si,listptr ; cx has type and string number
mov dirlist[si],cx ; update Director table from insertst
jmp dfkey7 ; show results and return success
dfkey5h:mov dx,offset strbad ; display complaint
mov ah,prstr
int dos
dfkeyx: jmp rskp
; define SINGLE CHAR replacement or CLEAR a key definition.
; cx has char count 1 (normal) or 0 (to undefine the key).
dfkey6: jcxz dfkey6c ; z = cx= 0, clear definition
mov al,byte ptr [si] ; get first byte from definition
xor ah,ah ; set the type bits to Char
mov si,listptr
mov dirlist[si],ax ; store type and key's new code
jmp dfkey7 ; return success
dfkey6c:push si ; clear a definition,
push di ; listptr points to current def
mov si,listptr ; starting address to clear
add si,offset dirlist
mov di,si ; destination
add si,2 ; source is next word
mov cx,nkeys ; current number of keys defined
add cx,cx ; double for listptr being words
sub cx,listptr ; cx = number of words to move
shr cx,1 ; convert to actual number of moves
jcxz dfkey6d ; z = none, just remove last word
push es
push ds
pop es ; make es:di point to datas segment
cld
push cx ; save cx
rep movsw ; move down higher list items
pop cx
mov si,listptr ; do keylist too, same way
add si,offset keylist
mov di,si
add si,2
rep movsw
pop es
dfkey6d:mov si,nkeys ; clear old highest list element
shl si,1 ; address words
mov dirlist[si],0 ; null the element
mov keylist[si],0 ; null the element
dec nkeys ; say one less key defined now
pop di ; restore saved registers
pop si
dfkey7: mov ah,msutake ; Finish up. In a Take file?
or ah,taklev ; or even directly
cmp ah,0
je dfkey7a ; e = no
cmp flags.takflg,0 ; echo Take commands?
je dfkey7b ; e = no
dfkey7a:mov ah,prstr ; display cr/lf
mov dx,offset crlf
int dos
call shkey0 ; show new definition (in SHKEY)
call shkfre ; show free string space
dfkey7b:jmp rskp ; return success
DFKEY ENDP
; SHOW KEY <cr> command. Call from Kermit level. Vectored here by SHOW
; command. Replaces obsolete procedure in msx---.
; Prompts for a key and shows that key's (or all if ? entered) keycode,
; definition, and the key definition free space remaining.
SHKEY PROC NEAR ; Show key's definition command
mov ah,cmcfm ; get a confirm
call comnd
nop ; ignore any additional text
nop
nop
push bx
mov dx,offset shkmsg1 ; ask for original key
mov ah,prstr
int dos
shky0: call getkey ; read keyboard, output to keycode
jc shky0 ; wait for a key (c = nothing there)
cmp byte ptr keycode,'?' ; query for all keys?
jne shky0a ; ne = no, not a query
test keycode,scan ; is this a scan code, vs ascii query?
jz shky0c ; z = no Scan, so it is a query
shky0a: mov ah,prstr ; show single key. Setup display
mov dx,offset crlf
int dos
call shkey0 ; show just one key
shky0b: call shkfre ; show free string space
jmp shkeyx ; exit
shky0c: mov cx,nkeys ; Show all keys. nkeys = number defined
jcxz shky0b ; z = none to show
mov si,offset keylist ; list of definitions
push si ; save pointer
shky1: pop si ; recover pointer
cld
lodsw ; get a keycode
push si ; save pointer
push cx ; save counter
mov keycode,ax ; save new keycode
mov ah,prstr
mov dx,offset crlf
int dos
call shkey0 ; show this keycode
pop cx ; pause between screens, recover cntr
push cx ; save it again
dec cx ; number yet to be shown
jcxz shky1b ; z = have now shown all of them
mov ax,nkeys ; number of defined keys
sub ax,cx ; minus number yet to be displayed
xor dx,dx ; clear extended numerator
div twelve ; two lines per definition display
or dx,dx ; remainder zero (12 defs shown)?
jnz shky1b ; nz = no, not yet so keep going
mov ah,prstr
mov dx,offset shkmsg3 ; "push any key to continue" msg
int dos
shky1a: call getkey ; get any key
jc shky1a ; c = nothing at keyboard yet, wait
shky1b: pop cx ; resume loop
loop shky1
pop si ; clean stack
call shkfre ; show free string space
jmp shkeyx ; exit
; show key worker routine, called from above
; SHKEY0 called by DFKEY just above
SHKEY0: test keycode,scan ; scan code?
jz shkey1 ; z = no, regular ascii
; SCAN codes
mov dx,offset scanmsg ; say Scan Code:
mov ah,prstr
int dos
mov ah,conout
mov dl,'\' ; add backslash before number
int dos
mov ax,keycode ; get key's code again
call decout ; display 16 bit decimal keycode
jmp shkey2 ; go get definition
shkey1: mov dx,offset ascmsg ; say ASCII CHAR
mov ah,prstr
int dos
mov dl,byte ptr keycode ; get ascii code (al part of input)
mov ah,conout
cmp dl,spc ; control code?
jae shkey1a ; ae = no
push dx ; save char
mov dl,5eh ; show caret first
int dos
pop dx
add dl,'A'-1 ; ascii bias
shkey1a:cmp dl,del ; DEL?
jne shkey1b ; ne = no
mov dl,'D' ; spell out DEL
int dos
mov dl,'E'
int dos
mov dl,'L'
shkey1b:int dos
mov dl,spc ; add a couple of spaces
int dos
int dos
mov dl,'\' ; add backslash before number
int dos
mov ax,keycode ; show 16 bit keycode in decimal
call decout ; and go get definiton
; Display defintion
shkey2: mov dx,offset shkmsg2 ; intermediate part of reply
mov ah,prstr ; " is defined as "
int dos
push di ; get a director code for this key
push cx
mov di,offset keylist ; list of keycodes
mov cx,nkeys ; number currently defined
jcxz shkey2a ; z = none
mov ax,keycode ; present keycode
push ds
pop es ; use datas segment for es:di
cld
repne scasw ; is current keycode in the list?
jne shkey2a ; ne = not in list
sub di,2 ; correct for auto increment
sub di,offset keylist
mov listptr,di ; list pointer for existing definition
pop cx
pop di
jmp shkey3 ; go process definition
shkey2a:pop cx
pop di
mov dx,offset noxmsg ; say Self (no translation)
mov ah,prstr
int dos
ret ; return to main show key loop
shkey3: ; translations, get kind of
mov si,listptr
test dirlist[si],verb ; defined as verb?
jnz shkey6 ; nz = yes, go do that one
test dirlist[si],strng ; defined as string?
jz shkey3a ; z = no
jmp shkey8 ; yes, do string display
shkey3a:
mov dx,offset ascmsg ; CHAR. say 'Ascii char:'
mov ah,prstr
int dos
mov ax,dirlist [si] ; get type and char
mov dl,al ; put char here for display
push ax ; save here too
mov ah,conout
cmp dl,spc ; control code?
jae shkey4 ; ae = no
push dx
mov dl,5eh ; show caret
int dos
pop dx
add dl,'A'-1 ; add ascii bias
shkey4: cmp dl,del ; DEL?
jne shkey4a ; ne = no
mov dl,'D' ; spell out DEL
int dos
mov dl,'E'
int dos
mov dl,'L'
shkey4a:int dos
mov dl,spc ; add a couple of spaces
mov ah,conout
int dos
int dos
mov dl,'\' ; add backslash before number
int dos
pop ax ; recover char
xor ah,ah ; clear high byte
call decout ; show decimal value
ret ; return to main show key loop
shkey6: mov ah,prstr ; VERB
mov dx,offset verbmsg ; say 'verb'
int dos
mov si,listptr ; get verb index from director
mov dx,dirlist[si]
and dx,not(verb+strng) ; remove type bits, leaves verb number
mov bx,offset kverbs ; table of verbs & actions
mov al,byte ptr [bx] ; number of keywords
xor ah,ah
dec ax
mov kwcnt,ax ; save number of last one here
cmp dx,ax ; asking for more than we have?
ja shkeyx ; a = yes, exit bad
inc bx ; point to first slot
mov cx,0 ; current slot number
shkey6b:cmp cx,dx ; this slot?
je shkey6c ; e = yes, print the text part
ja shkeyx ; a = beyond, exit bad
mov al,byte ptr [bx] ; get cnt (keyword length)
xor ah,ah
add ax,4 ; skip over '$' and two byte value
add bx,ax ; bx = start of next keyword slot
inc cx ; current keyword number
jmp short shkey6b ; try another
shkey6c:inc bx ; look at text field
mov dx,bx ; offset for printing
mov ah,prstr
int dos
mov ah,conout
mov dl,spc ; add a couple of spaces
int dos
int dos
mov dl,'\' ; show verb name as \Kverb
int dos
mov dl,'K'
int dos
mov ah,prstr
mov dx,bx ; show name part again
int dos
ret ; return to main show key loop
shkey8: mov ah,prstr ; STRING
mov dx,offset strngmsg ; say String:
int dos
mov si,listptr ; get index from director
mov bx,dirlist[si]
and bx,not(verb+strng) ; remove type bits
shl bx,1 ; index words
mov si,sptable[bx] ; table of string offsets
mov cl,byte ptr [si] ; get string length byte
xor ch,ch
inc si ; point to string text
mov ah,conout
shkey8a:cld
lodsb ; get a byte
cmp al,spc ; control code?
jae shkey8b ; ae = no
push ax
mov dl,5eh ; show caret first
int dos
pop ax
add al,40h ; convert to printable for display
shkey8b:mov dl,al
int dos ; display it
loop shkey8a ; do another
ret ; return to main show key loop
shkeyx: pop bx ; restore reg
jmp rskp ; return success
SHKEY ENDP
;;; keyboard translator local support procedures, system independent
; Tstkeyw checks text word pointed to by si against table of keywords (pointed
; to by kverbs, made by mkeyw macro); returns in bx either action value or 0.
; Returns in kbtemp the number of the keyword and carry clear, or if failure
; returns kbtemp zero and carry set.
; Keyword structure is: db cnt (length of string 'word')
; db 'word' (keyword string)
; db '$' (printing terminator)
; dw value (value returned in bx)
; Make these with macro mkeyw such as mkeyw 'test',15 with the list of
; such keywords headed by a byte giving the number of keywords in the list.
tstkeyw proc near
push ax
push cx
push si
mov verblen,0 ; verblen will hold verb length
push si ; save user's verb pointer
tstkw1: cld
lodsb ; get a verb character
cmp al,spc ; verbs are all non-spaces and above
jbe tstkw2 ; be = done (space or control char)
inc verblen ; count verb length
jmp short tstkw1 ; printable char, look for more
tstkw2: pop si ; pointer to verb
mov bx,offset kverbs ; table of Kermit verb keywords
mov al,byte ptr [bx] ; number of keywords
xor ah,ah
mov kwcnt,ax ; save number of keywords here
inc bx ; point bx to first slot
mov kbtemp,0 ; remember which keyword
tstkw3: ; match table keyword and text word
mov cx,verblen ; length of user's verb
cmp byte ptr [bx],cl ; compare length vs table keyword
jne tstkw4 ; ne = not equal lengths, try another
push si ; lengths match, how about spelling?
push bx
inc bx ; point at start of keyword
tstkw3a:mov ah,byte ptr [bx] ; keyword char
mov al,byte ptr [si] ; text char
cmp ah,'A'
jb tstkw3b ; b = control chars
cmp ah,'Z'
ja tstkw3b ; a = not upper case alpha
add ah,'a'-'A' ; convert upper case to lower case
tstkw3b:cmp al,'A'
jb tstkw3c
cmp al,'Z'
ja tstkw3c
add al,'a'-'A' ; convert upper case to lower case
tstkw3c:cmp al,ah ; test characters
jne tstkw3d ; ne = no match
inc si ; move to next char
inc bx
loop tstkw3a ; loop through entire length
tstkw3d:pop bx
pop si
jcxz tstkw5 ; z: cx = 0, exit with match;
; else select next keyword
tstkw4: inc kbtemp ; number of keyword to test next
mov cx,kbtemp
cmp cx,kwcnt ; all done? Recall kbtemp starts at 0
jae tstkwx ;ae = exhausted search, unsuccessfully
mov al,byte ptr [bx] ; cnt (keyword length from macro)
xor ah,ah
add ax,4 ; skip over '$' and two byte value
add bx,ax ; bx = start of next keyword slot
jmp tstkw3 ; do another comparison
tstkw5: ; get action pointer
mov al,byte ptr [bx] ; cnt (keyword length from macro)
xor ah,ah
add ax,2 ; skip over '$'
add bx,ax ; now bx points to dispatch value
mov bx,[bx] ; bx holds dispatch value
clc ; carry clear for success
jmp short tstkwxx ; exit
ret
tstkwx: xor bx,bx ; exit when no match
mov kbtemp,bx ; make verb number be zero too
stc ; carry set for failure
tstkwxx:pop si
pop cx
pop ax
ret
tstkeyw endp
; Insert asciiz string pointed to by si into string buffer stbuf.
; Reg cx has string length upon entry.
; Success: returns offset of first free byte (strmax) in string buffer stbuf,
; cx = type and Index of new string, and carry clear.
; Failure = carry set.
insertst proc near
push bx
push dx
push si
push di
push kbtemp ; save this variable too
mov dx,cx ; save length of incoming string in dx
mov bx,offset sptable ; table of string offsets
mov kbtemp,0 ; slot number
mov cx,maxstng ; number of entries, find an empty slot
insert1:cmp word ptr[bx],0 ; slot empty?
je insert2 ; e = yes
inc kbtemp ; remember slot number
add bx,2 ; look at next slot
loop insert1 ; keep looking
jmp short insert4 ; get here if no empty slots
insert2: ; see if stbuf has sufficient space
mov cx,dx ; length of new string to cx
mov di,strmax ; offset of first free byte in stbuf
add di,cx ; di = address where this string would end
cmp di,offset stbuf+stbuflen ; beyond end of buffer?
jae insert4 ; ae = yes, not enough room
mov di,strmax ; point to first free slot in stbuf
mov [bx],di ; fill slot with address offset of buffer
push es
push ds
pop es ; point es:di to datas segment
cld
mov byte ptr [di],cl ; length of text for new string
inc di ; move to next storage slot
rep movsb ; copy string text
pop es
mov strmax,di ; offset of next free byte
mov cx,kbtemp ; return new slot number with Director Index
and cx,not(strng+verb) ; clear type bits
or cx,strng ; say type is multi-char string
clc ; say success
jmp short insertx ; exit
insert4:stc ; say no-can-do
insertx:pop kbtemp
pop di
pop si
pop dx
pop bx
ret
insertst endp
; Remove (delete) string. Enter with listptr preset for director entry.
; Acts only on existing multi-char strings; recovers freed space.
; All registers preserved.
remstr proc near
push si
mov si,listptr ; list pointer
test dirlist[si],strng ; multi-char string?
pop si
jnz remst1 ; nz = a multi-char string
ret ; else do nothing
remst1: push ax
push bx
push cx
push dx
push si
mov si,listptr
mov ax,dirlist[si] ; Director table entry
and ax,not(strng+verb) ; clear type bits, leave string's pointer
mov dirlist[si],0 ; clear Director table entry
shl ax,1 ; index words not bytes
mov si,offset sptable ; list of string offsets in stbuf
add si,ax ; plus index = current slot
mov bx,[si] ; get offset of string to be deleted
mov dx,bx ; save in dx for later
mov cl,byte ptr [bx] ; get length byte
xor ch,ch ; get length of subject string
inc cx ; length byte too, cx has whole length
sub strmax,cx ; count space to be freed (adj end-of-buf ptr)
mov word ptr [si],0 ; clear sptable of subject string address
push cx ; save length of purged string
push di ; save di
push si
push es ; save es
push ds
pop es ; setup es:di to be ds:offset of string
mov di,dx ; destination = start address of purged string
mov si,dx ; source = start address of purged string
add si,cx ; plus string length of purged string
mov cx,offset stbuf+stbuflen ; 1 + address of buffer end
sub cx,si ; 1 + number of bytes to move
dec cx ; number of bytes to move
jcxz remst2 ; z = none
cld ; direction is forward
rep movsb ; move down preserved strings
remst2: pop es ; restore regs
pop di
pop si
pop ax ; recover length of purged string (was in cx)
mov bx,offset sptable ; string pointer table
mov cx,maxstng ; max mumber of entries
remst4: cmp [bx],dx ; does this entry occur before purged string?
jbe remst5 ; be = before or equal, so leave it alone
sub [bx],ax ; recompute address (remove old string space)
remst5: add bx,2 ; look at next list entry
loop remst4 ; do all entries in sptable
pop si
pop dx
pop cx
pop bx
pop ax
ret
remstr endp
shkfre proc near ; show free key & string defs & space
push ax ; preserves all registers
push bx
push cx
push dx
push kbtemp
mov dx,offset fremsg
mov ah,prstr
int dos
mov ax,maxkeys ; max number of key defs
sub ax,nkeys ; number currently used
call decout ; show the value
mov ah,prstr
mov dx,offset kyfrdef ; give key defs msg
int dos
mov bx,offset sptable ; table of string pointers
mov cx,maxstng ; number of pointers
mov kbtemp,0 ; number free
shkfr1: cmp word ptr [bx],0 ; slot empty?
jne shkfr2 ; ne = no
inc kbtemp ; count free defs
shkfr2: add bx,2 ; look at next slot
loop shkfr1 ; do all of them
mov ax,kbtemp ; number of free defs
call decout ; display
mov dx,offset stfrdef ; say free string defs
mov ah,prstr
int dos
mov ax,offset stbuf+stbuflen ; 1 + last byte in stbuf
sub ax,strmax ; offset of last free byte in stbuf
call decout
mov dx,offset stfrspc ; give free space part of msg
mov ah,prstr
int dos
pop kbtemp
pop dx
pop cx
pop bx
pop ax
ret
shkfre endp
; Initialize the keyboard tables at Kermit startup time. Optional procedure.
; Requires kbdinlst to be configured with mkeyw macro in the form
; mkeyw 'definition',keytype*256+keycode
; keytype is 0 for scan codes and non-zero for ascii.
; Returns normally.
kbdinit proc near ; read keyword kbdinlst and setup
push ds ; initial keyboard assignments
pop es ; set es:di to datas segment
mov taklev,1 ; pretend that we are in Take file
mov si,offset kbdinlst ; start of list of definitions
kbdini1:mov cl,byte ptr [si] ; cnt field (keyword length of macro)
xor ch,ch
jcxz kbdinix ; z = null cnt field = end of list
inc si ; look at text field
mov di,offset tranbuf ; where defkey expects text
cld
rep movsb ; copy cx chars to tranbuf
mov byte ptr [di],0 ; insert null terminator
inc si ; skip '$' field
mov ax,word ptr [si] ; get value field
mov keycode,ax ; set key ident value
push si
call dfkey2 ; put dfkey to work
nop
nop
nop
pop si
add si,2 ; point to next entry
jmp kbdini1 ; keep working
kbdinix:mov taklev,0 ; reset Take file level
ret
kbdinit endp
;;; End of System Independent Procedures
;;; Begin System Dependent Procedures
; Read keyboard. System dependent.
; Return carry set if nothing at keyboard.
; If char present return carry clear with key's code in Keycode.
; If key is ascii put that in the low byte of Keycode and clear bit Scan in
; the high byte; otherwise, put the scan code in the lower byte and set bit
; Scan in the high byte.
; Bit Scan is set if key is not an ascii code.
; Modifies register ax.
getkey proc near
mov keycode,0
call iseof ; is stdin at eof?
jnc getky5 ; nc = not eof, get more
mov al,trans.escchr ; Kermit's escape char
mov byte ptr keycode,al ; save ascii char
clc ; to get out gracefully at EOF
ret ; and exit
getky5: mov ah,dconio ; check console
mov dl,0ffh ; input desired
int dos
jnz getky1 ; nz = char available
stc ; carry set = nothing available
jmp short getkyx ; exit on no char available
getky1: cmp al,0 ; scan code being returned?
jne getky1a ; ne = no
mov ah,dconio ; read second byte (scan code)
mov dl,0ffh
int dos
jz getkyx ; z = nothing there
mov ah,al ; scan code goes here
mov al,0 ; ascii code goes here
getky1a:
push di ; check key (ax) for aliases
push cx
push es
mov di,offset aliaskey ; list of aliased keys
mov cx,aliaslen ; number of entries
jcxz getky2 ; z = no entries
push ds
pop es ; make es:di point to datas segment
cld
repne scasw ; look for a match
jne getky2 ; ne = not there
mov al,0 ; force use of scan code (in ah)
getky2: pop es
pop cx
pop di
or al,al ; scan code being returned?
jnz getky3 ; nz = no
xchg ah,al ; put scan code in ident area
or keycode,scan ; set scan flag (vs ascii)
getky3: mov byte ptr keycode,al ; return key's code (usually ascii)
clc ; carry clear = got a char
getkyx: ret
getkey endp
postkey proc near ; do sys dep action after reading
ret ; key during active translation
postkey endp
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret.
R PROC NEAR
ret
R ENDP
code ends
end