home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / extra / nyenhuis2.arc / MSUGEN.ASM < prev    next >
Assembly Source File  |  1989-05-14  |  50KB  |  1,381 lines

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