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

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