home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / extra / nyenhuis2.arc / MSUHP1.ASM < prev    next >
Assembly Source File  |  1988-07-01  |  52KB  |  1,434 lines

  1.     NAME    msuhp1
  2. ; File MSUHP1.ASM 
  3. ; Keyboard translator, by Joe R. Doupnik, Dec 1986
  4. ;  with contributions from David L. Knoell.
  5. ; For HP 150 Kermit (DOS level i/o)
  6. ; edit history:
  7. ; Last edit 4 June 1988
  8. ; 1 July 1988 Version 2.31
  9. ; 4 June 1988 Add changes at dfkey1e, dfkey12, add test to read from files
  10. ; 2 Jan 1988 version 2.30
  11.  
  12.     include    mssdef.h
  13.  
  14.     public    keybd, dfkey, shkey, msuinit
  15.  
  16. ; some definitions
  17.  
  18. maxkeys    equ    128            ; maximum number of key definitions
  19. maxstng    equ    64            ; maximum number of multi-char strings
  20. stbuflen equ    1000            ; length of string buffer (bytes)
  21.  
  22. verb    equ    8000h            ; dirlist flag: use verb action table
  23. strng    equ    4000h            ; dirlist flag: use string action table
  24. scan    equ    100h            ; keycode flag: code is scan not ascii
  25. braceop    equ    7bh            ; opening curly brace
  26. bracecl    equ    7dh            ; closing curly brace
  27.  
  28. datas    segment    public 'datas'
  29.     extrn taklev:byte, comand:byte, intake:byte, flags:byte
  30.     extrn shkadr:word, stkadr:word, trans:byte
  31.                         ; system dependent references
  32.     
  33. ;;;    System Independent local storage
  34.  
  35. tranbuf    db    132 dup (?)        ; 132 byte translator work buffer
  36. crlf    db    cr,lf,'$'
  37. dfhelp1    db    cr,lf,' Enter key',27h,'s identification as a character',cr,lf
  38.     db    '  or as its numerical equivalent \{b##} of ascii',cr,lf
  39.     db    '  or as its scan code \{b##}'
  40.     db    cr,lf,'  or as SCAN followed by its scan code',cr,lf
  41.     db    '    where b is O for octal, X for hex, or D for decimal'
  42.     db    ' (default).',cr,lf,'    Braces {} are optional.'
  43.     db    cr,lf,'    Follow the identification with the new definition.'
  44.     db    cr,lf,' or CLEAR to restore initial key settings.$'
  45. dfaskky    db    cr,lf,' Push key to be defined: $'
  46. dfaskdf    db    cr,lf,' Enter new definition: $'
  47. verbbad    db    cr,lf,' No such verb',cr,lf,'$'
  48. strbad    db    cr,lf,' Not enough space for new string',cr,lf,'$'
  49. keyfull    db    cr,lf,' No more space to define keys',cr,lf,'$'
  50. dfkopps    db    cr,lf,' Opps! That is Kermit',27h,'s Escape Char.'
  51.     db    ' Translation is not permitted.',cr,lf,'$'
  52. shkmsg1    db    cr,lf,'Push key to be shown (? shows all): $'
  53. shkmsg2    db    ' decimal is defined as',cr,lf,'$'
  54. shkmsg3    db    cr,lf,'... more, push any key to continue ...$'
  55. kwarnmsg db    cr,lf,' Notice: this form of Set Key is obsolete$'
  56.  
  57. ascmsg    db    ' Ascii char: $'
  58. scanmsg    db    ' Scan Code $'
  59. strngmsg db    ' String: $'
  60. verbmsg    db    ' Verb: $'
  61. noxmsg    db    ' Self, no translation.$'
  62. fremsg    db    cr,lf,' Free space: $'
  63. kyfrdef    db    ' key and $'
  64. stfrdef db    ' string definitions, $'
  65. stfrspc    db    ' string characters.',cr,lf,'$'
  66.                     ; translation tables
  67. keylist    dw    maxkeys dup (?)        ; 16 bit keycodes, paralled by dirlist
  68. dirlist    dw    maxkeys dup (?)        ; director {v+s} + {index | new char}
  69. sptable    dw    maxstng dup (?)        ; list of asciiz string offsets
  70. stbuf    dw    stbuflen dup (?)    ; buffer for strings
  71. strmax    dw    stbuf            ; first free byte in stbuf
  72. listptr    dw    ?            ; item number for keylist and dirlist
  73. nkeys    dw    ?            ; number of actively defined keys
  74. keycode    dw    ?            ; ascii/scan code for key
  75. kbtemp    dw    ?            ; scratch storage for translator
  76. brace    db    ?            ; brace detected flag byte
  77. oldform    db    ?            ; old form Set Key, if non-zero
  78. verblen    dw    ?            ; length of user's verb (work temp)
  79. kwcnt    dw    ?            ; number of keywords (work temp)
  80. msutake    db    ?            ; if being run from take file or not
  81. twelve    dw    12d
  82. dosflg    db    0
  83. ;;;    End System Independent Data Area
  84.  
  85. ;;;    System Dependent Data Area
  86. ;    edit dfhelp2 to include nice list of verbs for this system.
  87. dfhelp2 db    cr,lf,' Enter either \{Kverb}  for a Kermit action verb',cr,lf
  88.     db    ' or a replacement string  (single byte binary numbers are'
  89.     db    ' \{b##})',cr,lf,' or nothing at all to undefine a key.'
  90.     db    cr,lf,' Braces {} are optional, and strings maybe enclosed in'
  91.     db    ' them.',cr,lf,' Strings may not begin with the character'
  92.     db    ' combinations of  \k  or  \{k',cr,lf
  93.     db    '    (start with a { brace instead).',cr,lf,lf
  94.     db    ' Verbs are as follows:',cr,lf
  95.     db    ' break, help, prtscn, status, exit'
  96.     db    cr,lf,'$'
  97.  
  98.     ; Aliaskey: keys having aliases - same ascii code but more than one
  99.     ; scan code, as on auxillary keypads. Use just scan codes with these.
  100.     ; Alternative use: force ascii keys to report out just scan codes.
  101.     ; Table format: high byte = scan code, low byte = ascii code. 
  102.     ; Contents are machine dependent.
  103. aliaskey db    0
  104. aliaslen equ    ($-aliaskey) shr 1    ; number of words in aliaskey table
  105.  
  106. kverbs    db    5            ; number of table entries below
  107.     mkeyw    'prtscn',trnprs        ; independent of ordering and case!
  108.     mkeyw    'break',sendbr        ; mkeyw 'name',procedure entry point
  109.     mkeyw    'help',cquery
  110.     mkeyw    'status',cstatus
  111.     mkeyw    'exit',cquit
  112.  
  113.                 ; Initialization data.
  114. kbdinlst equ    this byte     ; Kermit IBM initialization time keyboard setup
  115.     dw    0        ; end of table marker
  116.  
  117. datas    ends
  118. ;            Documentation
  119. ;Translating a key:
  120. ;   The translator is called to obtain keyboard input; it sends characters to
  121. ; the serial port through standard controlled echo procedures or invokes
  122. ; named procedures. It returns carry clear when its operation is completed
  123. ; for normal actions and carry set when Connect mode must be exited. When
  124. ; Connect mode is exited the just read char should be passed in Kbdflg 
  125. ; to msster.asm for invoking actions such as Status, send a break,
  126. ; quit connect mode; system dependent procedure Term is responsible for this. 
  127. ;
  128. ;  Principal procedures are -
  129. ;    msuinit        Initializes keyboard translator in this file when
  130. ;            Kermit first begins. Installs dfkey and shkey as the
  131. ;            procedures used for Set Key and Show Key. Sys Indep.
  132. ;            Called from msx or msy init procs. System Independent.
  133. ;    keybd        Performs the translation, outputs chars to the serial
  134. ;            port or invokes a Kermit action routine. Sys Indep.
  135. ;    dfkey        Defines a key's translation. Reads command line
  136. ;            via Kermit's command parser comnd. System Independent.
  137. ;    shkey        Shows translation of a key. Requests user to push
  138. ;            selected key. System Independent.
  139. ;
  140. ;    kbdinit        optional. Initializes the translation tables when
  141. ;            Kermit starts up. Called by msuinit. System Dependent.
  142. ;    getkey        Performs the keyboard read and returns results in
  143. ;            a standardized system independent format. Sys Depend.
  144. ;    postkey        called by active translator after obtaining a keycode.
  145. ;            Used to provide extra local actions (keyclick) only
  146. ;            in Connect mode (not during Set/Show key commands).
  147. ;            Called by keybd. System dependent.
  148. ; Supporting system independent procedures are -
  149. ; shkfre (show string free space), tstkeyw (finds user's keyword in the verb
  150. ; table), insertst (insert string in buffer), remstr (delete string in buffer).
  151. ;
  152. ;   System dependent procedure Getkey reads a keycode (usually via a Bios
  153. ; call). On IBM compatible machines this yields <ah=scan code, al=ascii>
  154. ; for ordinary keys, or <ah=scan code, al=0> for special keys such as F1,
  155. ; or <ah=0, al=###> when Alt### is used.
  156. ; For any system, the canonical output form is the key's code in Keycode.
  157. ; Place the ascii code (or scan code if none) in byte Keycode and ancillary
  158. ; info (shift states plus marker bit for scan codes) in byte Keycode + 1.
  159. ;   Table Aliaskey is a list of scan code/ascii codes for keys which appear
  160. ; more than once on a keyboard. This list is examined to distinguish such
  161. ; aliased keys (those on an auxillary keypad) from an ordinary ascii key,
  162. ; and the aliased key is then referenced by its scan code rather than by
  163. ; the ordinary ascii code. Aliaskey is machine and keyboard dependent.
  164. ;
  165. ;    Procedure Keybd calls Getkey for the Keycode, checks list of translatable
  166. ; keys Keylist, and then either sends an ascii string (one or more characters)
  167. ; or invokes a Kermit action verb. List Dirlist indicates what kind of 
  168. ; translation to do. Keybd is system independent but may contain system
  169. ; dependent special actions such as echoing keyclicks. Keybd calls system
  170. ; dependent procedure Postkey just after calling getkey so local actions
  171. ; such as keyclicks can be activated only during Connect mode operations.
  172. ;
  173. ;    Keylist is a packed but unordered list of 16 bit keycodes which need
  174. ; translation. The lower order byte holds a key code (ascii char or scan code)
  175. ; while the high byte holds a scan code marker bit (0 if ascii code in low
  176. ; byte) plus any ancillary keyboard information such as Control/Shift/Alt/Meta
  177. ; keys being held down; these are of use in Show Key presentations.
  178. ;    Dirlist parallels Keylist to provide the kind of translation, verb or
  179. ; string, in the two highest bits with the other bits holding either
  180. ; a single new replacement character or the item number in lists of verbs
  181. ; or strings. If neither verb nor strng type bits are set in a dirlist
  182. ; word then the translation is a single new character held in the lower
  183. ; eight bits of that dirlist word.
  184. ;
  185. ;    The number of key translations is assembly constant Maxkeys (def 128).
  186. ;    The maximum number of strings is assembly constant Maxstngs (def 64).
  187. ;    The maximum number of verbs is 256 and is set by building table Kverbs.
  188. ;
  189. ;   For verbs, use the Item number from the Director table Dirlist to select
  190. ; a procedure offset from the structured list Kverbs and jump to that offset.
  191. ; Most verb procedures return carry clear to stay within Connect mode.
  192. ; Verbs requiring exiting Connect mode return carry set and may set byte
  193. ; Kbdflg to a char code which will be read by msster.asm for activating a
  194. ; transient Kermit action such as send a break (Kbdflg = 'b').
  195. ; Kbdflg is stored in msster.asm (as zero initially, meaning ignore it).
  196. ; Action verb procedures are normally located in a system dependent file.
  197. ;
  198. ;   For multi-char strings, use Item number from Director table Dirlist to
  199. ; select a pointer to a string. The list of string pointers is Sptable
  200. ; (string pointer table) which holds the offset in the data segment of the
  201. ; strings stored in buffer Stbuf. In stbuf strings are held as: one byte of
  202. ; length of following text and then the text itself (permits embedded nulls).
  203. ;  Use Chrout to send each string character, and finally return from Keybd
  204. ; with carry clear.
  205. ;
  206. ;   For single character replacements obtain the new character from the lower
  207. ; order byte of Director table Dirlist. If the character is Kermit's present
  208. ; escape character return from Keybd carry set to leave connect mode.
  209. ; Otherwise, send the character via Chrout and return from Keybd carry clear.
  210.  
  211. ; Keylist table format:
  212. ;    7 bits   1 bit   8 bits
  213. ; +----------+----+------------+ scan bit = 1 if key's code is non-ascii
  214. ; | aux info |scan| key's code | aux info = system dependent, used only to
  215. ; +----------+----+------------+            help identify key
  216. ;
  217. ; Dirlist table format          v s    meaning
  218. ;   1   1      14 bits         0 0    copy out one byte translation
  219. ; +---+---+--------------------+  1 0    copy out multi-char string number Item
  220. ; | v | s | item # or new char |  0 1    do action verb number Item
  221. ; +---+---+--------------------+  1 1    (not used)
  222. ;
  223. ; Table kverbs is organized by macro mkeyw as -
  224. ;    kverbs    db    number of table entries
  225. ;    (each entry is in the form below:)
  226. ;        db    number of bytes in verbname
  227. ;        db    'verbname'        variable length
  228. ;        db    '$'            for printing
  229. ;        dw    value            offset of procedure
  230. ;
  231. ;
  232. ;   Dfkey defines a key to be itself (undefines it) or a single replacement
  233. ; character or a character string or a Kermit action verb. Dfkey requires
  234. ; a command line so that it may be invoked by Take files but can be forced
  235. ; to prompt an interactive user to push a key. Syntax is discussed below.
  236. ; Note that redefined keys have their old definitions cleared so that
  237. ; old string space is reclaimed automatically.
  238. ;
  239. ;   Shkey displays a key's definition and the user is asked to push the
  240. ; selected key. The free space for strings is always shown afterward. See
  241. ; below for syntax.
  242. ;
  243. ;   Kbdinit is an optional routine called when Kermit starts up. It fills in
  244. ; the translation tables with desirable default values to save having to
  245. ; use long mskermit.ini files. The default values are stored in a structured
  246. ; table similar to (but not the same as) Dfkey's command lines; the keycode
  247. ; values are preset by hand to 16 bit numbers.
  248.  
  249. ;Defining a key:
  250. ; Command is SET KEY <key ident><whitespace><definition>
  251. ;
  252. ; <key ident> is
  253. ;        a single ordinary ascii char or
  254. ;        the numerical equivalent of an ascii char or
  255. ;        a Scan Code written as a number or
  256. ;        keyword SCAN followed by a number.
  257. ;        ?    Displays help message.
  258. ;    Numbers and Binary codes are of the form
  259. ;        \123    a decimal number
  260. ;        \o456    an octal number        base letters o, d, x can be
  261. ;        \d213    a decimal number    upper or lower case
  262. ;        \x0d    a hex number
  263. ;        \{b###}  braces around above material following slash.
  264. ;
  265. ; <whitespace> is one or more spaces and or tabs.
  266. ;
  267. ; <definition> is
  268. ;    missing altogether which "undefines" a key.
  269. ;    \Kverb        for a Kermit action verb; upper or lower case K is ok
  270. ;    \{Kverb}    ditto. Verb is the name of an action verb.
  271. ;    text        a string with allowed embedded whitespace and embedded
  272. ;            binary chars as above. This kind of string may not
  273. ;            commence with sequences \K or \{K; use braces below.
  274. ;    {text}        string confined to material within but excluding
  275. ;            the braces. Note, where the number of opening braces
  276. ;            exceeds the number of closing braces the end of line
  277. ;            terminates the string: {ab{}{{c}d ==> ab{}{{c}d
  278. ;            but  {ab}{{c}d ==> ab.
  279. ;    ?        Displays help message and lists all action verbs.
  280. ;
  281. ;    If Set Key is given interactively, as opposed to within a Take
  282. ;    file, the system will prompt for inputs if none is on the command
  283. ;    line. The response to Push key to be defined cannot be edited.
  284. ;
  285. ;    Text which reduces to a single replacement character is put into a
  286. ;    table separate from the multi-character strings (maxstng of these).
  287. ;    A key may be translated into any single 8 bit code.
  288. ;    
  289. ;    Comments can follow a Kermit action verb or a braced string; no
  290. ;    semicolon is required since all are stripped out by the Take file
  291. ;    reader before the defining text is seen by SET KEY.
  292. ;
  293. ;    The current Kermit escape character cannot be translated without
  294. ;    subtrafuge.
  295. ;
  296. ;    Examples:
  297. ;        Set Key q z
  298. ;                makes key q send character z
  299. ;        Set Key \7 \27[0m
  300. ;                makes key Control G send the four byte
  301. ;                string  ESC [ 0 m
  302. ;        Set Key q
  303. ;                undefines key q so it sends itself (q) again.
  304. ;        Set Key \2349 \kexit
  305. ;                defines IBM Alt-X to invoke the leave connect
  306. ;                mode verb "exit" (Kermit's escape-char ^] C).
  307. ;        Set Key \x0c Login \{x0d}myname\{x0d}mypass\x0d
  308. ;                defines Control L to send the string
  309. ;                Login <cr>myname<cr>mypass<cr>
  310. ;
  311. ; Alternative Set Key syntax for backward compatibility with previous versions
  312. ;    The same forms as above except the key identification number must
  313. ;    be decimal and must Not have a leading backslash. Example:
  314. ;    Set Key Scan 59 This is the F1 key
  315. ;
  316. ;    If the definition is omitted it may be placed on the following line;
  317. ;    if that line is also empty the key is undefined (defined as Self).
  318. ;    A warning message about obsolete syntax will be given followed by
  319. ;    the key's modern numerical value and new definition. Only "special"
  320. ;    keys (those not producing ascii codes) are compatible with this
  321. ;    translator.
  322. ;
  323. ;Showing a key:
  324. ; Command is SHOW KEY <cr>
  325. ; System prompts user to press a key and shows the definition plus the
  326. ; free space for strings. Query response results in showing all definitions.
  327. ;            End Documentation
  328.  
  329. code    segment    public 'code'
  330.         ; system independent external items
  331.     extrn    comnd:near, prompt:near, iseof:near    ; in msscmd
  332.     extrn    isfile:near, strlen:near        ; in mssfil
  333.     extrn    cnvlin:near, katoi:near, decout:near    ; in mssset
  334.         ; system dependent external items
  335.         ; these are system dependent action verbs, in msxhp1
  336.     extrn    beep:near, trnprs:near, sendbr:near
  337.     extrn    chrout:near, cstatus:near, cquit:near, cquery:near
  338.  
  339.     assume    cs:code, ds:datas, es:datas
  340.  
  341. ; Begin system independent Keyboard Translator code
  342.  
  343. ; MSUINIT performs Kermit startup initialization for this file.
  344. ; Note, shkadr and stkadr are pointers tested by Set/Show Key calls. If they
  345. ; are not initialized here then the older Set/Show Key procedures are called.
  346. MSUINIT    PROC    NEAR            ; call from msx/msy init code
  347.     call    kbdinit            ; optional: init translator tables
  348.     mov    shkadr,offset shkey    ; declare keyboard translator present
  349.     mov    stkadr,offset dfkey    ; via Show and Set Key proc addresses
  350.     ret
  351. MSUINIT    ENDP
  352.  
  353. ; Call Keybd to read a keyboard char (just returns carry clear if none) and
  354. ; 1) send the replacement string (or original char if not translated)
  355. ;    out the serial port, or
  356. ; 2) execute a Kermit action verb.
  357. ; Returns carry set if Connect mode is to be exited, else carry clear.
  358. ; Modifies registers ax and bx. 
  359. KEYBD    PROC    NEAR            ; active translator
  360.     call    getkey            ; read keyboard
  361.     jnc    keybd1            ; nc = data available
  362.     jmp    keybdx            ; else just return carry clear
  363. keybd1:    call    postkey            ; call system dependent post processor
  364.     cmp    nkeys,0            ; is number of keys defined = 0?
  365.     jz    keybd3            ; z = none defined
  366.     push    di            ; search keylist for this keycode
  367.     push    cx            ; save some registers    
  368.     push    es
  369.     mov    di,offset keylist    ; list of defined keycode words
  370.     mov    ax,keycode        ; present keycode
  371.     mov    cx,nkeys        ; number of words to examine
  372.     push    ds
  373.     pop    es            ; make es:di point to datas segment
  374.     cld
  375.     repne    scasw            ; find keycode in list
  376.     pop    es            ; restore regs
  377.     pop    cx
  378.     je    keybd1b            ; e = found, work with present di
  379.     pop    di            ; restore original di
  380.     test    keycode,scan        ; is this a scan code?
  381.     jz    keybd3            ; z = no, it's ascii, use al as char
  382.     call    beep            ; say key is a dead one
  383.     clc
  384.     ret                ; and exit with no action
  385.  
  386. keybd1b:sub    di,2            ; correct for auto increment
  387.     sub    di,offset keylist    ; subtract start of list ==> listptr
  388.     mov    ax,dirlist[di]        ; ax = contents of director word
  389.     pop    di            ; restore original di
  390.                     ; dispatch on Director code
  391.     test    ax,verb            ; verb only?
  392.     jnz    keyvb            ; e = yes
  393.     test    ax,strng        ; multi-char string only?
  394.     jnz    keyst            ; e = yes, else single char & no xlat
  395.                     ;
  396.                     ; do single CHAR output (char in al)
  397. keybd3:    cmp    al,trans.escchr        ; Kermit's escape char?
  398.     je    keybd3a            ; e = yes, handle separately
  399.     call    chrout            ; transmit the char
  400.     clc                ; return success
  401.     ret
  402. keybd3a:stc                ; set carry for jump to Quit
  403.     ret
  404.  
  405. keyvb:    and    ax,not(verb+strng)    ; VERB (ax=index, remove type bits)
  406.     mov    bx,offset kverbs    ; start of verb table
  407.     cmp    al,byte ptr [bx]    ; index > number of entries?
  408.     jae    keybdx            ; ae = illegal, indices start at 0
  409.     inc    bx            ; bx points to first entry
  410.     push    cx            ; save reg
  411.     mov    cx,ax            ; save the index in cx
  412.     inc     cx            ; counter, indices start at 0
  413. keyvb1:    mov    al,byte ptr [bx]    ; cnt value
  414.     xor    ah,ah
  415.     add    ax,4            ; skip text and '?' and value word
  416.     add    bx,ax            ; look at next slot
  417.     loop    keyvb1            ; walk to correct slot
  418.     sub    bx,2            ; backup to value field
  419. keyvb2:    pop    cx            ; restore reg
  420.     mov    bx,[bx]            ; get value field of this slot
  421.     cmp    bx,0            ; jump address defined?
  422.     je    keybdx            ; e = no, skip the action
  423.     jmp    bx            ; perform the function
  424.  
  425. keyst:    and    ax,not(verb+strng)    ; STRING (ax=index, remove type bits)
  426.     shl    ax,1            ; convert to word index
  427.     push    si            ; save working reg
  428.     mov    si,ax            ; word subscript in table
  429.     mov    si,sptable[si]        ; memory offset of selected string
  430.     cmp    si,0            ; is there a string pointer present?
  431.     je    keyst3            ; e = no, skip operation
  432.     cld                ; scan forward
  433.     lodsb                ; get string length byte
  434.     mov    cl,al
  435.     xor    ch,ch            ; to cx for looping
  436.     jcxz    keybdx            ; z = null length
  437. keyst2:    lodsb                ; get new string char into al
  438.     push    si            ; save si and cx around call
  439.     push    cx
  440.     call    chrout            ; send out the char in al
  441.     pop    cx            ; recover regs
  442.     pop    si
  443.     loop    keyst2            ; loop through whole string
  444. keyst3:    pop    si            ; restore reg
  445.  
  446. keybdx:    clc                ; return success
  447.     ret
  448. KEYBD    ENDP
  449.  
  450. ; SET KEY - define a key   (procedure dfkey)
  451. ; SET KEY <key ident><whitespace><new meaning>
  452. ; Call from Kermit level. Returns as ret if failure or as rskp if success.
  453. ;  
  454. DFKEY    PROC    NEAR            ; define a key as a verb or a string
  455.     mov    keycode,0        ; clear keycode
  456.     mov    oldform,0        ; say no old form Set Key yet
  457.     mov    dx,offset tranbuf    ; our work space
  458.     mov    word ptr tranbuf,0    ; insert terminator
  459.     mov    bx,offset dfhelp1    ; first help message
  460.     mov    ah,cmfile        ; parse a word
  461.     call    comnd            ; get key code or original ascii char
  462.      nop
  463.      nop
  464.      nop
  465.     mov    al,intake        ; reading from Take file indirectly
  466.     or    al,taklev        ; ditto, directly
  467.     mov    msutake,al        ; save here
  468.     or    ah,ah            ; any text given?
  469.     jnz    dfkey12            ; nz = yes, so don't consider prompts
  470.                     ; interactive key request
  471.     cmp    intake,0        ; in a Take file?
  472.     je    dfkey10            ; e = no, prompt for keystroke
  473.     jmp    dfkey0            ;  else say bad syntax
  474. dfkey10:mov    ah,prstr
  475.     mov    dx,offset dfaskky    ; ask for key to be pressed
  476.     int    dos
  477. dfkey11:call    getkey            ; read key ident from keyboard
  478.     jc    dfkey11            ; c = no response, wait for keystroke
  479.     mov    ah,prstr        ; display cr/lf
  480.     mov    dx,offset crlf
  481.     int    dos
  482.     call    shkey0            ; show current definition (in SHKEY)
  483.     jmp    dfkey1e            ; prompt for and process definition
  484.  
  485. dfkey12:                ; Look for word SCAN and ignore it
  486.     mov    dx,word ptr tranbuf    ; get first two characters
  487.     or    dx,2020h        ; map upper to lower case
  488.     cmp    dx,'cs'            ; first two letters of word "scan"?
  489.     je    dfkey            ; e = yes, skip the word
  490.     cmp    dx,'lc'            ; first two letters of word "clear"?
  491.     je    dfkey15            ; e = yes, reinit keyboard [2.31]
  492.     cmp    dx,'fo'            ; first two letters of "off"
  493.     je    dfkey13            ; e = yes, use DOS keyboard calls
  494.     cmp    dx,'no'            ; first two letters of "on"
  495.     je    dfkey14            ; e = yes, use standard kbd calls
  496.     cmp    ah,1            ; number of characters received
  497.     ja    dfkey1            ; a = more than one, decode
  498.     mov    ah,byte ptr tranbuf    ; get the single char
  499.     mov    byte ptr keycode,ah    ; store as ascii keycode
  500.     jmp    dfkey1b            ; go get definition
  501.  
  502. dfkey13:mov    dosflg,0ffh        ; set DOS keyboard read flag
  503.     jmp    short dfkey14a
  504. dfkey14:mov    dosflg,0        ; clear DOS keyboard read flag
  505. dfkey14a:mov    ah,cmcfm        ; added after version 2.30
  506.     call    comnd
  507.      jmp    r
  508.      nop
  509.     jmp    rskp
  510.  
  511. dfkey15:mov    ah,cmcfm        ; added after version 2.30
  512.     call    comnd            ; confirm request before proceeding
  513.      jmp    r
  514.      nop
  515.     jmp    short dfkeyc        ; execute command
  516.  
  517. dfkey0:    mov    dx,offset dfhelp1    ; say bad definition command
  518.     mov    ah,prstr
  519.     int    dos
  520.     jmp    rskp
  521.  
  522. dfkeyc:                    ; CLEAR key defs, restore startup defs
  523.     mov    cx,maxkeys        ; size of keycode tables
  524.     push    es            ; save register
  525.     push    ds
  526.     pop    es            ; make es point to datas segment
  527.     mov    ax,0            ; null, value to be stored
  528.     mov    di,offset dirlist    ; director table
  529.     cld
  530.     rep    stosw            ; clear it
  531.     mov    cx,maxkeys
  532.     mov    di,offset keylist    ; keycode table
  533.     rep    stosw            ; clear it
  534.     pop    es            ; recover register
  535.     mov    strmax,offset stbuf    ; clear string buffer
  536.     mov    stbuf,0            ; 
  537.     mov    bx,offset sptable
  538.     mov    word ptr [bx],0        ; clear table of string pointers
  539.     mov    nkeys,0            ; clear number of defined keys
  540.     call    msuinit            ; restore startup definitions
  541.     jmp    rskp
  542.                     ; Multi-char key identification
  543. dfkey1:    mov    si,offset tranbuf    ; point to key ident text
  544.     cmp    byte ptr [si],'0'    ; is first character numeric?
  545.     jb    dfkey1a            ; b = no
  546.     cmp    byte ptr [si],'9'    ; in numbers?
  547.     ja    dfkey1a            ; a = no
  548.     mov    keycode,scan        ; setup keycode for scan value
  549.     mov    dx,si            ; get length of string in cx
  550.     call    strlen
  551.     push    ds
  552.     pop    es            ; make es point to datas segment
  553.     push    si
  554.     add    si,cx            ; point at string terminator
  555.     mov    di,si
  556.     inc    di            ; place to store string (1 byte later)
  557.     inc    cx            ; include null terminator
  558.     std                ; work backward
  559.     rep    movsb            ; move string one place later
  560.     cld
  561.     pop    si
  562.     mov    byte ptr [si],'\'    ; make ascii digits into \nnn form
  563.     mov    oldform,0ffh        ; set old form flag
  564.     mov    dx,offset kwarnmsg    ; tell user this is old form
  565.     mov    ah,prstr
  566.     int    dos
  567. dfkey1a:call    katoi            ; convert ascii number to binary in ax
  568.     jc    dfkey0            ; c = no number converted
  569.     or    keycode,ax        ; store in keycode
  570.  
  571. dfkey1b:                ; Get Definition proper
  572.     test    oldform,0ffh        ; old form Set Key active?
  573.     jz    dfkey1f            ; z = no
  574.     mov    bx,offset tranbuf    ; get new definition on main cmd line
  575.     mov    word ptr [bx],0        ; insert terminator
  576.     mov    dx,offset dfhelp2    ; help for definition of key
  577.     mov    ah,cmtxt        ; read rest of line into tranbuf
  578.     call    comnd
  579.      nop                ; allow null definitions
  580.      nop
  581.      nop
  582.     or    ah,ah            ; char count zero?
  583.     jz    dfkey1e            ; z = zero, prompt for definition
  584.     jmp    dfkey1g            ; process definition
  585.  
  586. dfkey1e:mov    ah,prstr
  587.     mov    dx,offset crlf
  588.     int    dos
  589.     mov    dx,offset dfaskdf    ; prompt for definition string
  590.      call    prompt            ; Kermit prompt routine
  591.     mov    comand.cmwhite,1    ; allow leading whitespace
  592.     mov    comand.cmcr,1        ; permit bare carriage returns
  593. dfkey1f:mov    bx,offset tranbuf    ; get new definition
  594.     mov    word ptr [bx],0        ; insert terminator
  595.     mov    dx,offset dfhelp2    ; help for definition of key
  596.     mov    ah,cmtxt        ; read rest of line into tranbuf
  597.     call    comnd
  598.      jmp r                ; exit now on ^C from user
  599.      nop
  600.     mov    comand.cmcr,0        ; turn off allowance for bare c/r's
  601. dfkey1g:xchg    ah,al            ; put byte count in al
  602.     xor    ah,ah            ; clear high byte
  603.     mov    kbtemp,ax        ; and save count in kbtemp
  604.     mov    ah,cmcfm        ; get a confirm
  605.     call    comnd
  606.      jmp    r            ; none so declare parse error
  607.      nop                ; round out to three bytes
  608.     mov    cx,kbtemp        ; string length
  609.     jcxz    dfkey2            ; z = empty string
  610.     push    si
  611.     push    di
  612.     mov    si,offset tranbuf    ; strip leading white space
  613. dfkey1c:cld                ; work forward
  614.     lodsb                ; read string char into al
  615.     dec    cx            ; number of chars left to read
  616.     cmp    al,' '            ; a space?
  617.     je    dfkey1c            ; e = yes, keep going
  618.     cmp    al,tab            ; tab?
  619.     je    dfkey1c            ; e = yes, keep going
  620.     dec    si            ; offset inc si in lodsb
  621.     add    cx,2            ; include terminator, offset dec above
  622.     jcxz    dfkey1d            ; z = nothing to move
  623.     mov    di,offset tranbuf    ; destination is start of buffer
  624.     push    ds
  625.     pop    es
  626.     cld
  627.     rep    movsb            ; copy text part of string
  628. dfkey1d:pop    di
  629.     pop    si
  630.     
  631. dfkey2:                    ; Examine translation
  632.     mov    al,trans.escchr        ; current escape char (port dependent)
  633.     cmp    al,byte ptr keycode    ; is this Kermit's escape char?
  634.     jne    dfkey2a            ; ne = no
  635.     test    keycode,scan        ; see if scan code
  636.     jnz    dfkey2a            ; nz = scan, so not ascii esc char
  637.     mov    dx,offset dfkopps    ; Opps! msg
  638.     mov    ah,prstr        ; complain and don't redefine
  639.     int    dos
  640.     jmp    rskp
  641.  
  642. dfkey2a:push    di            ; get a director code for this key
  643.     push    cx    
  644.     mov    di,offset keylist    ; list of keycodes
  645.     mov    cx,nkeys        ; number currently defined
  646.     mov    ax,keycode        ; present keycode
  647.     jcxz    dfkey2b            ; cx = 0 means none defined yet
  648.     cld
  649.     push    ds
  650.     pop    es
  651.     repne    scasw            ; is current keycode in the list?
  652.     jne    dfkey2b            ; ne = not in list
  653.     sub    di,2            ; correct for auto increment
  654.     sub    di,offset keylist
  655.     mov    listptr,di        ; list pointer for existing definition
  656.     pop    cx
  657.     pop    di
  658.     jmp    dfkey3            ; go process definition
  659.  
  660. dfkey2b:pop    cx            ; key not currently defined so
  661.     pop    di            ;  make a new director entry for it
  662.     mov    bx,nkeys        ; number of keys previously defined
  663.     cmp    bx,maxkeys        ; enough space?
  664.     jae    dfkey2c            ; ae = no, complain
  665.     shl    bx,1            ; count words
  666.     mov    listptr,bx        ; index into word list
  667.     mov    ax,keycode        ; get key's code
  668.     mov    keylist[bx],ax        ; store it in list of keycodes
  669.     mov    dirlist[bx],0        ; clear the new director entry
  670.     inc    nkeys            ; new number of keys
  671.     jmp    dfkey3            ; go process definition
  672.  
  673. dfkey2c:mov    dx,offset keyfull    ; say key space is full already
  674.     mov    ah,prstr
  675.     int    dos
  676.     jmp    rskp            ; tell parser we are happy
  677. ; listptr has element number in keylist or dirlist; keycode has key's code.
  678.  
  679. ; Parse new definition. First look for Kermit verbs as a line beginning
  680. ; as \K or \{K. Otherwise, consider the line to be a string.
  681. ; In any case, update the Director table for the new definition.
  682.  
  683. dfkey3:    mov    brace,0            ; assume not using braces
  684.     mov    si,offset tranbuf    ; start of definition text
  685.     cmp    byte ptr [si],'\'    ; starts with escape char?
  686.     jne    dfkey5            ; ne = no, so we have a string
  687.     inc    si            ; skip the backslash
  688.     cmp    byte ptr [si],braceop    ; starts with \{?
  689.     jne    dfkey3a            ; ne = no
  690.     inc    si            ; skip the opening brace
  691.     mov    brace,bracecl        ; expect closing brace
  692. dfkey3a:cmp    byte ptr [si],'K'    ; starts with \{K or \K?
  693.     je    dfkey3b            ; e = yes
  694.     cmp    byte ptr [si],'k'    ; starts as \{k or \k?
  695.     jne    dfkey5            ; ne = no, then it's a string
  696. dfkey3b:inc    si            ; yes, skip the K too
  697.                     ; Kermit action VERBS
  698.     push    si            ; save verb name start address
  699. dfkey4a:cld
  700.     lodsb                ; scan til closing brace or w/s or end
  701.     cmp    al,0            ; premature end?
  702.     je    dfkey4b            ; e = yes, accept without brace
  703.     cmp    al,brace        ; closing brace?
  704.     je    dfkey4b            ; e = yes
  705.     cmp    al,spc            ; white space or control char?
  706.     ja    short dfkey4a        ; a = no, so not at end yet
  707. dfkey4b:mov    byte ptr[si-1],0    ; insert null terminator
  708.     pop    si            ; recover start address
  709.     call    tstkeyw            ; find keyword, kw # returned in kbtemp
  710.     jc    dfkey4d            ; c = no keyword found, complain
  711.     call    remstr            ; clear old string, if string
  712.     mov    ax,kbtemp        ; save keyword number
  713.     and    ax,not(verb+strng)    ; clear verb / string field
  714.     or    ax,verb            ; set verb ident
  715.     mov    si,listptr
  716.     mov    dirlist[si],ax        ; store info in Director table
  717.     jmp    dfkey7            ; show results and return success
  718.  
  719. dfkey4d:mov    dx,offset verbbad    ; say no such verb
  720.     mov    ah,prstr
  721.     int    dos
  722.     jmp    rskp
  723.  
  724. ; Here we are left with the definition string; si points to its start, and
  725. ; kbtemp holds its length (number of bytes). Null termination. If the string
  726. ; begins with an opening brace it terminates on a matching closing brace
  727. ; or the end of line, whichever occurs first.
  728. ; Null length strings mean define key as Self.
  729.                     ; STRING definitions
  730. dfkey5:    mov    si,offset tranbuf    ; start of string text
  731.     cmp    byte ptr [si],braceop    ; opening brace?
  732.     jne    dfkey5f            ; ne = no, ignore brace-matching code
  733.     mov    dl,braceop        ; opening brace (we count them up)
  734.     mov    dh,bracecl        ; closing brace (we count them down)
  735.     mov    kbtemp,0        ; we are at brace level 0
  736. dfkey5b:cld                ; search forward
  737.     lodsb                ; read a string char
  738.     cmp    al,0            ; at end of string?
  739.     je    dfkey5d            ; e = yes, we are done
  740.     cmp    al,dl            ; an opening brace?
  741.     jne    dfkey5c            ; ne = no
  742.     inc    kbtemp            ; yes, increment brace level
  743.     jmp    short dfkey5b        ;  and continue scanning
  744. dfkey5c:cmp    al,dh            ; closing brace?
  745.     jne    dfkey5b            ; ne = no, continue scanning
  746.     dec    kbtemp            ; yes, decrement brace level
  747.     cmp    kbtemp,0        ; at level 0?
  748.     jne    dfkey5b            ; ne = no, #opening > #closing braces
  749.     mov    byte ptr [si-1],0    ; plant terminator on closing brace
  750. dfkey5d:mov    si,offset tranbuf+1    ; skip opening brace
  751.  
  752. dfkey5f:call    remstr            ; first, clear old string, if any
  753.     mov    di,offset tranbuf    ; si=source, di=dest, convert in-place
  754.     call    cnvlin            ; convert numbers, cx gets line length
  755.     mov    si,offset tranbuf    ; provide address of new string
  756.     cmp    cx,1            ; just zero or one byte to do?
  757.     jbe    dfkey6            ; e = yes, do as a char
  758.     call    insertst        ; insert new string, returns reg cx
  759.     jc    dfkey5h            ; c = could not do insert
  760.     mov    si,listptr        ; cx has type and string number
  761.     mov    dirlist[si],cx        ; update Director table from insertst
  762.     jmp    dfkey7            ; show results and return success
  763.  
  764. dfkey5h:mov    dx,offset strbad    ; display complaint
  765.     mov    ah,prstr
  766.     int    dos
  767. dfkeyx:    jmp    rskp
  768.  
  769.         ; define SINGLE CHAR replacement or CLEAR a key definition.
  770.         ; cx has char count 1 (normal) or 0 (to undefine the key).
  771. dfkey6:    jcxz    dfkey6c            ; z = cx= 0, clear definition
  772.     mov    al,byte ptr [si]    ; get first byte from definition
  773.     xor    ah,ah            ; set the type bits to Char
  774.     mov    si,listptr
  775.     mov    dirlist[si],ax        ; store type and key's new code
  776.     jmp    dfkey7            ; return success
  777.  
  778. dfkey6c:push    si            ; clear a definition,
  779.     push    di            ; listptr points to current def
  780.     mov    si,listptr        ; starting address to clear
  781.     add    si,offset dirlist
  782.     mov    di,si            ; destination
  783.     add    si,2            ; source is next word
  784.     mov    cx,nkeys        ; current number of keys defined
  785.     add    cx,cx            ; double for listptr being words
  786.     sub    cx,listptr        ; cx = number of words to move
  787.     shr    cx,1            ; convert to actual number of moves
  788.     jcxz    dfkey6d            ; z = none, just remove last word
  789.     push    es
  790.     push    ds
  791.     pop    es            ; make es:di point to datas segment
  792.     cld
  793.     push    cx            ; save cx
  794.     rep    movsw            ; move down higher list items
  795.     pop    cx
  796.     mov    si,listptr        ; do keylist too, same way
  797.     add    si,offset keylist
  798.     mov    di,si
  799.     add    si,2
  800.     rep    movsw
  801.     pop    es
  802. dfkey6d:mov    si,nkeys        ; clear old highest list element
  803.     shl    si,1            ; address words
  804.     mov    dirlist[si],0        ; null the element
  805.     mov    keylist[si],0        ; null the element
  806.     dec    nkeys            ; say one less key defined now
  807.     pop    di            ; restore saved registers
  808.     pop    si
  809.  
  810. dfkey7:    mov    ah,msutake        ; Finish up. In a Take file?
  811.     or    ah,taklev        ; or even directly
  812.     cmp    ah,0
  813.     je    dfkey7a            ; e = no
  814.     cmp    flags.takflg,0        ; echo Take commands?
  815.     je    dfkey7b            ; e = no
  816. dfkey7a:mov    ah,prstr        ; display cr/lf
  817.     mov    dx,offset crlf
  818.     int    dos
  819.     call    shkey0            ; show new definition (in SHKEY)
  820.     call    shkfre            ; show free string space
  821. dfkey7b:jmp    rskp            ; return success
  822. DFKEY    ENDP
  823.  
  824. ; SHOW KEY <cr> command. Call from Kermit level. Vectored here by SHOW
  825. ; command. Replaces obsolete procedure in msx---.
  826. ; Prompts for a key and shows that key's (or all if ? entered) keycode,
  827. ; definition, and the key definition free space remaining.
  828.  
  829. SHKEY    PROC    NEAR            ; Show key's definition command
  830.     mov    ah,cmcfm        ; get a confirm
  831.     call    comnd
  832.      nop                ; ignore any additional text
  833.      nop
  834.      nop
  835.     push    bx
  836.     mov    dx,offset shkmsg1    ; ask for original key
  837.     mov    ah,prstr
  838.     int    dos
  839. shky0:    call    getkey            ; read keyboard, output to keycode
  840.     jc    shky0            ; wait for a key (c = nothing there)
  841.     cmp    byte ptr keycode,'?'    ; query for all keys?
  842.     jne    shky0a            ; ne = no, not a query
  843.     test    keycode,scan        ; is this a scan code, vs ascii query?
  844.     jz    shky0c            ; z = no Scan, so it is a query
  845.  
  846. shky0a:    mov    ah,prstr        ; show single key. Setup display
  847.     mov    dx,offset crlf
  848.     int    dos
  849.     call    shkey0            ; show just one key
  850. shky0b:    call    shkfre            ; show free string space
  851.     jmp    shkeyx            ; exit
  852.  
  853. shky0c:    mov    cx,nkeys        ; Show all keys. nkeys = number defined
  854.     jcxz    shky0b            ; z = none to show
  855.     mov    si,offset keylist    ; list of definitions
  856.     push    si            ; save pointer
  857. shky1:    pop    si            ; recover pointer
  858.     cld
  859.     lodsw                ; get a keycode
  860.     push    si            ; save pointer
  861.     push    cx            ; save counter
  862.     mov    keycode,ax        ; save new keycode
  863.     mov    ah,prstr
  864.     mov    dx,offset crlf
  865.     int    dos
  866.     call    shkey0            ; show this keycode
  867.  
  868.     pop    cx            ; pause between screens, recover cntr
  869.     push    cx            ; save it again
  870.     dec    cx            ; number yet to be shown
  871.     jcxz    shky1b            ; z = have now shown all of them
  872.     mov    ax,nkeys        ; number of defined keys
  873.     sub    ax,cx            ; minus number yet to be displayed
  874.     xor    dx,dx            ; clear extended numerator
  875.     div    twelve            ; two lines per definition display
  876.     or    dx,dx            ; remainder zero (12 defs shown)?
  877.     jnz    shky1b            ; nz = no, not yet so keep going
  878.     mov    ah,prstr
  879.     mov    dx,offset shkmsg3    ; "push any key to continue" msg
  880.     int    dos
  881. shky1a:    call    getkey            ; get any key
  882.     jc    shky1a            ; c = nothing at keyboard yet, wait
  883. shky1b:    pop    cx            ; resume loop
  884.     loop    shky1
  885.     pop    si            ; clean stack
  886.     call    shkfre            ; show free string space
  887.     jmp    shkeyx            ; exit
  888.  
  889.         ; show key worker routine, called from above
  890.                     ; SHKEY0 called by DFKEY just above
  891. SHKEY0:    test    keycode,scan        ; scan code?
  892.     jz    shkey1            ; z = no, regular ascii
  893.  
  894.                     ; SCAN codes
  895.     mov    dx,offset scanmsg    ; say Scan Code:
  896.     mov    ah,prstr
  897.     int    dos
  898.     mov    ah,conout
  899.     mov    dl,'\'            ; add backslash before number
  900.     int    dos
  901.     mov    ax,keycode        ; get key's code again
  902.     call    decout            ; display 16 bit decimal keycode
  903.     jmp    shkey2            ; go get definition
  904.  
  905. shkey1:    mov    dx,offset ascmsg    ; say ASCII CHAR
  906.     mov    ah,prstr
  907.     int    dos
  908.     mov    dl,byte ptr keycode    ; get ascii code (al part of input)
  909.     mov    ah,conout
  910.     cmp    dl,spc            ; control code?
  911.     jae    shkey1a            ; ae = no
  912.     push    dx            ; save char
  913.     mov    dl,5eh            ; show caret first
  914.     int    dos
  915.     pop    dx
  916.     add    dl,'A'-1        ; ascii bias
  917. shkey1a:cmp    dl,del            ; DEL?
  918.     jne    shkey1b            ; ne = no
  919.     mov    dl,'D'            ; spell out DEL
  920.     int    dos
  921.     mov    dl,'E'
  922.     int    dos
  923.     mov    dl,'L'
  924. shkey1b:int    dos
  925.     mov    dl,spc            ; add a couple of spaces
  926.     int    dos
  927.     int    dos
  928.     mov    dl,'\'            ; add backslash before number
  929.     int    dos
  930.     mov    ax,keycode        ; show 16 bit keycode in decimal
  931.     call    decout            ; and go get definiton
  932.  
  933.                     ; Display defintion
  934. shkey2:    mov    dx,offset shkmsg2    ; intermediate part of reply
  935.     mov    ah,prstr        ; " is defined as "
  936.     int    dos
  937.     push    di            ; get a director code for this key
  938.     push    cx    
  939.     mov    di,offset keylist    ; list of keycodes
  940.     mov    cx,nkeys        ; number currently defined
  941.     jcxz    shkey2a            ; z = none
  942.     mov    ax,keycode        ; present keycode
  943.     push    ds
  944.     pop    es            ; use datas segment for es:di
  945.     cld
  946.     repne    scasw            ; is current keycode in the list?
  947.     jne    shkey2a            ; ne = not in list
  948.     sub    di,2            ; correct for auto increment
  949.     sub    di,offset keylist
  950.     mov    listptr,di        ; list pointer for existing definition
  951.     pop    cx
  952.     pop    di
  953.     jmp    shkey3            ; go process definition
  954.  
  955. shkey2a:pop    cx
  956.     pop    di
  957.     mov    dx,offset noxmsg    ; say Self (no translation)
  958.     mov    ah,prstr
  959.     int    dos
  960.     ret                ; return to main show key loop
  961.  
  962. shkey3:                    ; translations, get kind of
  963.     mov    si,listptr
  964.     test    dirlist[si],verb    ; defined as verb?
  965.     jnz    shkey6            ; nz = yes, go do that one
  966.     test    dirlist[si],strng    ; defined as string?
  967.     jz    shkey3a            ; z = no
  968.     jmp    shkey8            ; yes, do string display
  969. shkey3a:
  970.     mov    dx,offset ascmsg    ; CHAR. say 'Ascii char:'
  971.     mov    ah,prstr
  972.     int    dos
  973.     mov    ax,dirlist [si]        ; get type and char
  974.     mov    dl,al            ; put char here for display
  975.     push    ax            ; save here too
  976.     mov    ah,conout
  977.     cmp    dl,spc            ; control code?
  978.     jae    shkey4            ; ae = no
  979.     push    dx
  980.     mov    dl,5eh            ; show caret
  981.     int    dos
  982.     pop    dx
  983.     add    dl,'A'-1        ; add ascii bias
  984. shkey4:    cmp    dl,del            ; DEL?
  985.     jne    shkey4a            ; ne = no
  986.     mov    dl,'D'            ; spell out DEL
  987.     int    dos
  988.     mov    dl,'E'
  989.     int    dos
  990.     mov    dl,'L'
  991. shkey4a:int    dos
  992.     mov    dl,spc            ; add a couple of spaces
  993.     mov    ah,conout
  994.     int    dos
  995.     int    dos
  996.     mov    dl,'\'            ; add backslash before number
  997.     int    dos
  998.     pop    ax            ; recover char
  999.     xor    ah,ah            ; clear high byte
  1000.     call    decout            ; show decimal value
  1001.     ret                ; return to main show key loop
  1002.  
  1003. shkey6:    mov    ah,prstr        ; VERB
  1004.     mov    dx,offset verbmsg    ; say 'verb'
  1005.     int    dos
  1006.     mov    si,listptr        ; get verb index from director
  1007.     mov    dx,dirlist[si]
  1008.     and    dx,not(verb+strng)    ; remove type bits, leaves verb number
  1009.     mov    bx,offset kverbs    ; table of verbs & actions
  1010.     mov    al,byte ptr [bx]    ; number of keywords
  1011.     xor    ah,ah
  1012.     dec    ax
  1013.     mov    kwcnt,ax        ; save number of last one here
  1014.     cmp    dx,ax            ; asking for more than we have?
  1015.     ja    shkeyx            ; a = yes, exit bad
  1016.     inc    bx            ; point to first slot
  1017.     mov    cx,0            ; current slot number
  1018. shkey6b:cmp    cx,dx            ; this slot?
  1019.     je    shkey6c            ; e = yes, print the text part
  1020.     ja    shkeyx            ; a = beyond, exit bad
  1021.     mov    al,byte ptr [bx]    ; get cnt (keyword length)
  1022.     xor    ah,ah
  1023.     add    ax,4            ; skip over '$' and two byte value
  1024.     add    bx,ax            ; bx = start of next keyword slot
  1025.     inc    cx            ; current keyword number
  1026.     jmp    short shkey6b        ; try another
  1027. shkey6c:inc    bx            ; look at text field
  1028.     mov    dx,bx            ; offset for printing
  1029.     mov    ah,prstr
  1030.     int    dos
  1031.     mov    ah,conout
  1032.     mov    dl,spc            ; add a couple of spaces
  1033.     int    dos
  1034.     int    dos
  1035.     mov    dl,'\'            ; show verb name as \Kverb
  1036.     int    dos
  1037.     mov    dl,'K'
  1038.     int    dos
  1039.     mov    ah,prstr
  1040.     mov    dx,bx            ; show name part again
  1041.     int    dos
  1042.     ret                ; return to main show key loop
  1043.  
  1044. shkey8:    mov    ah,prstr        ; STRING
  1045.     mov    dx,offset strngmsg    ; say String:
  1046.     int    dos
  1047.     mov    si,listptr        ; get index from director
  1048.     mov    bx,dirlist[si]
  1049.     and    bx,not(verb+strng)    ; remove type bits
  1050.     shl    bx,1            ; index words
  1051.     mov    si,sptable[bx]        ; table of string offsets
  1052.     mov    cl,byte ptr [si]    ; get string length byte
  1053.     xor    ch,ch
  1054.     inc    si            ; point to string text
  1055.     mov    ah,conout
  1056. shkey8a:cld
  1057.     lodsb                ; get a byte
  1058.     cmp    al,spc            ; control code?
  1059.     jae    shkey8b            ; ae = no
  1060.     push    ax
  1061.     mov    dl,5eh            ; show caret first
  1062.     int    dos
  1063.     pop    ax
  1064.     add    al,40h            ; convert to printable for display
  1065. shkey8b:mov    dl,al
  1066.     int    dos            ; display it
  1067.     loop    shkey8a            ; do another
  1068.     ret                ; return to main show key loop
  1069.     
  1070. shkeyx:    pop    bx            ; restore reg
  1071.     jmp    rskp            ; return success
  1072. SHKEY    ENDP
  1073.  
  1074. ;;;    keyboard translator local support procedures, system independent
  1075.  
  1076. ; Tstkeyw checks text word pointed to by si against table of keywords (pointed
  1077. ; to by kverbs, made by mkeyw macro); returns in bx either action value or 0.
  1078. ; Returns in kbtemp the number of the keyword and carry clear, or if failure
  1079. ; returns kbtemp zero and carry set.
  1080. ; Keyword structure is:         db    cnt    (length of string 'word')
  1081. ;                 db    'word'    (keyword string)
  1082. ;                 db    '$'    (printing terminator)
  1083. ;                 dw    value    (value returned in bx)
  1084. ; Make these with macro mkeyw such as   mkeyw 'test',15   with the list of
  1085. ; such keywords headed by a byte giving the number of keywords in the list.
  1086. tstkeyw    proc    near
  1087.     push    ax
  1088.     push    cx
  1089.     push    si
  1090.     mov    verblen,0        ; verblen will hold verb length
  1091.     push    si            ; save user's verb pointer
  1092. tstkw1:    cld
  1093.     lodsb                ; get a verb character
  1094.     cmp    al,spc            ; verbs are all non-spaces and above
  1095.     jbe    tstkw2            ; be = done (space or control char)
  1096.     inc    verblen            ; count verb length
  1097.     jmp    short tstkw1        ; printable char, look for more
  1098. tstkw2:    pop    si            ; pointer to verb
  1099.     mov    bx,offset kverbs    ; table of Kermit verb keywords
  1100.     mov    al,byte ptr [bx]    ; number of keywords
  1101.     xor    ah,ah
  1102.     mov    kwcnt,ax        ; save number of keywords here
  1103.     inc    bx            ; point bx to first slot
  1104.     mov    kbtemp,0        ; remember which keyword
  1105.  
  1106. tstkw3:                    ; match table keyword and text word
  1107.     mov    cx,verblen        ; length of user's verb
  1108.     cmp    byte ptr [bx],cl    ; compare length vs table keyword
  1109.     jne    tstkw4            ; ne = not equal lengths, try another
  1110.     push    si            ; lengths match, how about spelling?
  1111.     push    bx
  1112.     inc    bx            ; point at start of keyword
  1113. tstkw3a:mov    ah,byte ptr [bx]    ; keyword char
  1114.     mov    al,byte ptr [si]    ; text char
  1115.     cmp    ah,'A'
  1116.     jb    tstkw3b            ; b = control chars
  1117.     cmp    ah,'Z'
  1118.     ja    tstkw3b            ; a = not upper case alpha
  1119.     add    ah,'a'-'A'        ; convert upper case to lower case
  1120. tstkw3b:cmp    al,'A'
  1121.     jb    tstkw3c
  1122.     cmp    al,'Z'
  1123.     ja    tstkw3c
  1124.     add    al,'a'-'A'        ; convert upper case to lower case
  1125. tstkw3c:cmp    al,ah            ; test characters
  1126.     jne    tstkw3d            ; ne = no match
  1127.     inc     si            ; move to next char
  1128.     inc    bx
  1129.     loop    tstkw3a            ; loop through entire length
  1130. tstkw3d:pop    bx
  1131.     pop    si
  1132.     jcxz    tstkw5            ; z: cx = 0, exit with match;
  1133.                     ;  else select next keyword
  1134. tstkw4:    inc    kbtemp            ; number of keyword to test next
  1135.     mov    cx,kbtemp
  1136.     cmp    cx,kwcnt        ; all done? Recall kbtemp starts at 0
  1137.     jae    tstkwx            ;ae = exhausted search, unsuccessfully
  1138.     mov    al,byte ptr [bx]    ; cnt (keyword length from macro)
  1139.     xor    ah,ah
  1140.     add    ax,4            ; skip over '$' and two byte value
  1141.     add    bx,ax            ; bx = start of next keyword slot
  1142.     jmp    tstkw3            ; do another comparison
  1143.  
  1144. tstkw5:                    ; get action pointer
  1145.     mov    al,byte ptr [bx]    ; cnt (keyword length from macro)
  1146.     xor    ah,ah
  1147.     add    ax,2            ; skip over '$'
  1148.     add    bx,ax            ; now bx points to dispatch value
  1149.     mov    bx,[bx]            ; bx holds dispatch value
  1150.     clc                ; carry clear for success
  1151.     jmp    short tstkwxx        ; exit
  1152.     ret
  1153. tstkwx:    xor    bx,bx            ; exit when no match
  1154.     mov    kbtemp,bx        ; make verb number be zero too
  1155.     stc                ; carry set for failure
  1156. tstkwxx:pop    si
  1157.     pop    cx
  1158.     pop    ax
  1159.     ret
  1160. tstkeyw    endp
  1161.  
  1162. ; Insert asciiz string pointed to by si into string buffer stbuf.
  1163. ; Reg cx has string length upon entry.
  1164. ; Success: returns offset of first free byte (strmax) in string buffer stbuf,
  1165. ; cx = type and Index of new string, and carry clear.
  1166. ; Failure = carry set.
  1167. insertst proc    near
  1168.     push    bx
  1169.     push    dx
  1170.     push    si
  1171.     push    di
  1172.     push    kbtemp        ; save this variable too
  1173.     mov    dx,cx        ; save length of incoming string in dx
  1174.     mov    bx,offset sptable ; table of string offsets
  1175.     mov    kbtemp,0    ; slot number
  1176.     mov    cx,maxstng    ; number of entries, find an empty slot
  1177. insert1:cmp    word ptr[bx],0    ; slot empty?
  1178.     je    insert2        ; e = yes
  1179.     inc    kbtemp        ; remember slot number
  1180.     add    bx,2        ; look at next slot
  1181.     loop    insert1        ; keep looking
  1182.     jmp    short insert4    ; get here if no empty slots
  1183. insert2:            ; see if stbuf has sufficient space
  1184.     mov    cx,dx        ; length of new string to cx
  1185.     mov    di,strmax    ; offset of first free byte in stbuf
  1186.     add    di,cx        ; di = address where this string would end
  1187.     cmp    di,offset stbuf+stbuflen ; beyond end of buffer?
  1188.     jae    insert4        ; ae = yes, not enough room
  1189.     mov    di,strmax    ; point to first free slot in stbuf
  1190.     mov    [bx],di        ; fill slot with address offset of buffer
  1191.     push    es
  1192.     push    ds
  1193.     pop    es        ; point es:di to datas segment
  1194.     cld
  1195.     mov    byte ptr [di],cl ; length of text for new string
  1196.     inc    di        ; move to next storage slot
  1197.     rep    movsb        ; copy string text
  1198.     pop    es
  1199.     mov    strmax,di    ; offset of next free byte
  1200.     mov    cx,kbtemp    ; return new slot number with Director Index
  1201.     and    cx,not(strng+verb) ; clear type bits
  1202.     or    cx,strng    ; say type is multi-char string
  1203.     clc            ; say success
  1204.     jmp    short insertx    ; exit
  1205. insert4:stc            ; say no-can-do
  1206. insertx:pop    kbtemp
  1207.     pop    di
  1208.     pop    si
  1209.     pop    dx
  1210.     pop    bx
  1211.     ret
  1212. insertst endp
  1213.  
  1214. ; Remove (delete) string. Enter with listptr preset for director entry.
  1215. ; Acts only on existing multi-char strings; recovers freed space.
  1216. ; All registers preserved.
  1217. remstr    proc    near        
  1218.     push    si
  1219.     mov    si,listptr        ; list pointer
  1220.     test    dirlist[si],strng    ; multi-char string?
  1221.     pop    si
  1222.     jnz    remst1            ; nz = a multi-char string
  1223.     ret                ; else do nothing
  1224. remst1:    push    ax
  1225.     push    bx
  1226.     push    cx
  1227.     push    dx
  1228.     push    si
  1229.     mov    si,listptr
  1230.     mov    ax,dirlist[si]         ; Director table entry
  1231.     and    ax,not(strng+verb) ; clear type bits, leave string's pointer
  1232.     mov    dirlist[si],0        ; clear Director table entry
  1233.     shl    ax,1            ; index words not bytes
  1234.     mov    si,offset sptable     ; list of string offsets in stbuf
  1235.     add    si,ax            ; plus index = current slot
  1236.     mov    bx,[si]            ; get offset of string to be deleted
  1237.     mov    dx,bx            ; save in dx for later
  1238.     mov    cl,byte ptr [bx]    ; get length byte
  1239.     xor    ch,ch            ; get length of subject string
  1240.     inc    cx            ; length byte too, cx has whole length
  1241.     sub    strmax,cx    ; count space to be freed (adj end-of-buf ptr)
  1242.     mov    word ptr [si],0    ; clear sptable of subject string address
  1243.     push    cx            ; save length of purged string
  1244.     push    di            ; save di
  1245.     push    si
  1246.     push    es            ; save es
  1247.     push    ds
  1248.     pop    es        ; setup es:di to be ds:offset of string
  1249.     mov    di,dx        ; destination = start address of purged string
  1250.     mov    si,dx        ; source = start address of purged string
  1251.     add    si,cx        ;  plus string length of purged string
  1252.     mov    cx,offset stbuf+stbuflen ; 1 + address of buffer end
  1253.     sub    cx,si            ; 1 + number of bytes to move
  1254.     dec    cx            ; number of bytes to move
  1255.     jcxz    remst2            ; z = none
  1256.     cld                ; direction is forward
  1257.     rep    movsb            ; move down preserved strings
  1258. remst2:    pop    es            ; restore regs
  1259.     pop    di
  1260.     pop    si
  1261.     pop    ax        ; recover length of purged string (was in cx)
  1262.     mov    bx,offset sptable     ; string pointer table
  1263.     mov    cx,maxstng        ; max mumber of entries
  1264. remst4:    cmp    [bx],dx        ; does this entry occur before purged string?
  1265.     jbe    remst5        ; be = before or equal, so leave it alone
  1266.     sub    [bx],ax        ; recompute address (remove old string space)
  1267. remst5:    add    bx,2            ; look at next list entry
  1268.     loop    remst4            ; do all entries in sptable
  1269.     pop    si
  1270.     pop    dx
  1271.     pop    cx
  1272.     pop    bx
  1273.     pop    ax
  1274.     ret
  1275. remstr    endp
  1276.  
  1277. shkfre    proc    near            ; show free key & string defs & space
  1278.     push    ax            ; preserves all registers
  1279.     push    bx
  1280.     push    cx
  1281.     push    dx
  1282.     push    kbtemp
  1283.     mov    dx,offset fremsg
  1284.     mov    ah,prstr
  1285.     int    dos
  1286.     mov    ax,maxkeys        ; max number of key defs
  1287.     sub    ax,nkeys        ; number currently used
  1288.     call    decout            ; show the value
  1289.     mov    ah,prstr
  1290.     mov    dx,offset kyfrdef    ; give key defs msg
  1291.     int    dos
  1292.     mov    bx,offset sptable    ; table of string pointers
  1293.     mov    cx,maxstng        ; number of pointers
  1294.     mov    kbtemp,0        ; number free
  1295. shkfr1:    cmp    word ptr [bx],0        ; slot empty?
  1296.     jne    shkfr2            ; ne = no
  1297.     inc    kbtemp            ; count free defs
  1298. shkfr2:    add    bx,2            ; look at next slot
  1299.     loop    shkfr1            ; do all of them
  1300.     mov    ax,kbtemp        ; number of free defs
  1301.     call    decout            ; display
  1302.     mov    dx,offset stfrdef    ; say free string defs
  1303.     mov    ah,prstr
  1304.     int    dos
  1305.     mov    ax,offset stbuf+stbuflen ; 1 + last byte in stbuf
  1306.     sub    ax,strmax        ; offset of last free byte in stbuf
  1307.     call    decout
  1308.     mov    dx,offset stfrspc    ; give free space part of msg
  1309.     mov    ah,prstr
  1310.     int    dos
  1311.     pop    kbtemp
  1312.     pop    dx
  1313.     pop    cx
  1314.     pop    bx
  1315.     pop    ax
  1316.     ret
  1317. shkfre    endp
  1318.  
  1319. ; Initialize the keyboard tables at Kermit startup time. Optional procedure.
  1320. ; Requires kbdinlst to be configured with mkeyw macro in the form
  1321. ;    mkeyw    'definition',keytype*256+keycode
  1322. ; keytype is 0 for scan codes and non-zero for ascii.
  1323. ; Returns normally.
  1324. kbdinit    proc     near            ; read keyword kbdinlst and setup
  1325.     push    ds            ;  initial keyboard assignments
  1326.     pop    es            ; set es:di to datas segment
  1327.     mov    taklev,1        ; pretend that we are in Take file
  1328.     mov    si,offset kbdinlst    ; start of list of definitions
  1329. kbdini1:mov    cl,byte ptr [si]    ; cnt field (keyword length of macro)
  1330.     xor    ch,ch
  1331.     jcxz    kbdinix            ; z = null cnt field = end of list
  1332.     inc    si            ; look at text field
  1333.     mov    di,offset tranbuf    ; where defkey expects text
  1334.     cld
  1335.     rep    movsb            ; copy cx chars to tranbuf
  1336.     mov    byte ptr [di],0        ; insert null terminator
  1337.     inc    si            ; skip '$' field
  1338.     mov    ax,word ptr [si]    ; get value field
  1339.     mov    keycode,ax        ; set key ident value
  1340.     push    si
  1341.     call    dfkey2            ; put dfkey to work
  1342.      nop
  1343.      nop
  1344.      nop
  1345.     pop    si
  1346.     add    si,2            ; point to next entry
  1347.     jmp    kbdini1            ; keep working
  1348. kbdinix:mov    taklev,0        ; reset Take file level
  1349.     ret
  1350. kbdinit    endp
  1351. ;;;    End of System Independent Procedures
  1352.  
  1353. ;;;    Begin System Dependent Procedures
  1354.  
  1355. ; Read keyboard. System dependent.
  1356. ; Return carry set if nothing at keyboard.
  1357. ; If char present return carry clear with key's code in Keycode.
  1358. ; If key is ascii put that in the low byte of Keycode and clear bit Scan in
  1359. ; the high byte; otherwise, put the scan code in the lower byte and set bit
  1360. ; Scan in the high byte.
  1361. ; Bit Scan is set if key is not an ascii code.
  1362. ; Modifies register ax.
  1363. getkey    proc    near
  1364.     mov    keycode,0
  1365.     call    iseof            ; is stdin at eof?
  1366.     jnc    getky5            ; nc = not eof, get more
  1367.      mov    al,trans.escchr        ; Kermit's escape char
  1368.     mov    byte ptr keycode,al    ; save ascii char
  1369.     clc                ;  to get out gracefully at EOF
  1370.     ret                ; and exit
  1371. getky5:    mov    ah,dconio        ; check console
  1372.     mov    dl,0ffh            ; input desired
  1373.     int    dos
  1374.     jnz    getky1            ; nz = char available
  1375.     stc                ; carry set = nothing available
  1376.     jmp    short getkyx        ; exit on no char available
  1377. getky1:    cmp    al,0            ; scan code being returned?
  1378.     jne    getky1a            ; ne = no
  1379.     mov    ah,dconio        ; read second byte (scan code)
  1380.     mov    dl,0ffh
  1381.     int    dos
  1382.     jz    getkyx            ; z = nothing there
  1383.     mov    ah,al            ; scan code goes here
  1384.     mov    al,0            ; ascii code goes here
  1385. getky1a:
  1386.     push    di            ; check key (ax) for aliases
  1387.     push    cx
  1388.     push    es
  1389.     mov    di,offset aliaskey    ; list of aliased keys
  1390.     mov    cx,aliaslen        ; number of entries
  1391.     jcxz    getky2            ; z = no entries
  1392.     push    ds
  1393.     pop    es            ; make es:di point to datas segment
  1394.     cld
  1395.     repne    scasw            ; look for a match
  1396.     jne    getky2            ; ne = not there
  1397.     mov    al,0            ; force use of scan code (in ah)
  1398. getky2:    pop    es
  1399.     pop    cx
  1400.     pop    di
  1401.     or    al,al            ; scan code being returned?
  1402.     jnz    getky3            ; nz = no
  1403.     xchg    ah,al            ; put scan code in ident area
  1404.     or    keycode,scan        ; set scan flag (vs ascii)
  1405. getky3:    mov    byte ptr keycode,al    ; return key's code (usually ascii)
  1406.     clc                ; carry clear = got a char
  1407. getkyx:    ret
  1408. getkey    endp
  1409.  
  1410.  
  1411. postkey    proc    near            ; do sys dep action after reading 
  1412.     ret                ; key during active translation
  1413. postkey    endp
  1414.  
  1415. ; Jumping to this location is like retskp.  It assumes the instruction
  1416. ;   after the call is a jmp addr.
  1417.  
  1418. RSKP    PROC    NEAR
  1419.     pop bp
  1420.     add bp,3
  1421.     push bp
  1422.     ret
  1423. RSKP    ENDP
  1424.  
  1425. ; Jumping here is the same as a ret.
  1426.  
  1427. R    PROC    NEAR
  1428.     ret
  1429. R    ENDP
  1430.  
  1431. code    ends
  1432.     end
  1433.