home *** CD-ROM | disk | FTP | other *** search
/ Phoenix CD 2.0 / Phoenix_CD.cdr / 01e / msk230s2.zip / MSUGEN.ASM < prev    next >
Assembly Source File  |  1988-02-12  |  71KB  |  1,398 lines

  1.         NAME    msugen
  2. ; File MSUGEN.ASM
  3. ; Keyboard translator, by Joe R. Doupnik, Dec 1986
  4. ;  with contributions from David L. Knoell.
  5. ; For Generic keyboard reading (via DOS)
  6. ; edit history:
  7. ; Last edit 1 Jan 1988
  8. ; 1 Jan 1988 version 2.30
  9.  
  10.         include mssdef.h
  11.  
  12.         public  keybd, dfkey, shkey, msuinit
  13.  
  14. ; some definitions
  15.  
  16. maxkeys equ     128                     ; maximum number of key definitions
  17. maxstng equ     64                      ; maximum number of multi-char strings
  18. stbuflen equ    1000                    ; length of string buffer (bytes)
  19.  
  20. verb    equ     8000h                   ; dirlist flag: use verb action table
  21. strng   equ     4000h                   ; dirlist flag: use string action table
  22. scan    equ     100h                    ; keycode flag: code is scan not ascii
  23. braceop equ     7bh                     ; opening curly brace
  24. bracecl equ     7dh                     ; closing curly brace
  25.  
  26. datas   segment public 'datas'
  27.         extrn taklev:byte, comand:byte, intake:byte, flags:byte
  28.         extrn shkadr:word, stkadr:word, trans:byte
  29.                                                 ; system dependent references
  30.  
  31. ;;;     System Independent local storage
  32.  
  33. tranbuf db      132 dup (?)             ; 132 byte translator work buffer
  34. crlf    db      cr,lf,'$'
  35. dfhelp1 db    cr,lf,' Enter key',27h,'s identification as a character',cr,lf
  36.         db      '  or as its numerical equivalent \{b##} of ascii',cr,lf
  37.         db      '  or as its scan code \{b##}'
  38.         db      cr,lf,'  or as SCAN followed by its scan code',cr,lf
  39.         db      '    where b is O for octal, X for hex, or D for decimal'
  40.         db      ' (default).',cr,lf,'    Braces {} are optional.'
  41.         db      cr,lf,'    Follow the identification with the new definition.'
  42.         db      cr,lf,' or CLEAR to restore initial key settings.$'
  43. dfaskky db      cr,lf,' Push key to be defined: $'
  44. dfaskdf db      ' Enter new definition: $'
  45. verbbad db      cr,lf,' No such verb',cr,lf,'$'
  46. strbad  db      cr,lf,' Not enough space for new string',cr,lf,'$'
  47. keyfull db      cr,lf,' No more space to define keys',cr,lf,'$'
  48. dfkopps db      cr,lf,' Opps! That is Kermit',27h,'s Escape Char.'
  49.         db      ' Translation is not permitted.',cr,lf,'$'
  50. shkmsg1 db      cr,lf,'Push key to be shown (? shows all): $'
  51. shkmsg2 db      ' decimal is defined as',cr,lf,'$'
  52. shkmsg3 db      cr,lf,'... more, push any key to continue ...$'
  53. kwarnmsg db     cr,lf,' Notice: this form of Set Key is obsolete$'
  54.  
  55. ascmsg  db      ' Ascii char: $'
  56. scanmsg db      ' Scan Code $'
  57. strngmsg db     ' String: $'
  58. verbmsg db      ' Verb: $'
  59. noxmsg  db      ' Self, no translation.$'
  60. fremsg  db      cr,lf,' Free space: $'
  61. kyfrdef db      ' key and $'
  62. stfrdef db      ' string definitions, $'
  63. stfrspc db      ' string characters.',cr,lf,'$'
  64.                                         ; translation tables
  65. keylist dw      maxkeys dup (0)         ; 16 bit keycodes, paralled by dirlist
  66. dirlist dw      maxkeys dup (0)         ; director {v+s} + {index | new char}
  67. sptable dw      maxstng dup (0)         ; list of asciiz string offsets
  68. stbuf   dw      stbuflen dup (0)        ; buffer for strings
  69. strmax  dw      stbuf                   ; first free byte in stbuf
  70. listptr dw      0                       ; item number for keylist and dirlist
  71. nkeys   dw      0                       ; number of actively defined keys
  72. keycode dw      0                       ; ascii/scan code for key
  73. kbtemp  dw      0                       ; scratch storage for translator
  74. brace   db      0                       ; brace detected flag byte
  75. oldform db      0                       ; old form Set Key, if non-zero
  76. verblen dw      0                       ; length of user's verb (work temp)
  77. kwcnt   dw      0                       ; number of keywords (work temp)
  78. msutake db      0                       ; if being run from take file or not
  79. twelve  dw      12d
  80.  
  81. ;;;     End System Independent Data Area
  82.  
  83. ;;;     System Dependent Data Area
  84. ;       edit dfhelp2 to include nice list of verbs for this system.
  85. dfhelp2 db      cr,lf,' Enter either \{Kverb}  for a Kermit action verb',cr,lf
  86.         db      ' or a replacement string  (single byte binary numbers are'
  87.         db      ' \{b##})',cr,lf,' or nothing at all to undefine a key.'
  88.         db      cr,lf,' Braces {} are optional, and strings maybe enclosed in'
  89.         db      ' them.',cr,lf,' Strings may not begin with the character'
  90.         db      ' combinations of  \k  or  \{k',cr,lf
  91.         db      '    (start with a { brace instead).',cr,lf,lf
  92.         db      ' Verbs are as follows:',cr,lf
  93.         db      ' Logoff (suspend logging), Logon (resume logging),'
  94.         db      ' DOS (push to), null (send a)',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      10                      ; 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   'Hangup',chang
  110.         mkeyw   'null',snull
  111.         mkeyw   'help',cquery
  112.         mkeyw   'status',cstatus
  113.         mkeyw   'exit',cquit
  114.         mkeyw   'DOS',kdos
  115.         mkeyw   'Logoff',klogof
  116.         mkeyw   'Logon',klogon
  117.                                 ; Initialization data.
  118. kbdinlst equ    this byte     ; Kermit IBM initialization time keyboard setup
  119.         mkeyw   '\x7f',8        ; Backspace key sends DEL
  120.         dw      0               ; end of table marker
  121.  
  122. datas   ends
  123.  
  124. ;                       Documentation
  125. ;Translating a key:
  126. ;   The translator is called to obtain keyboard input; it sends characters to
  127. ; the serial port through standard controlled echo procedures or invokes
  128. ; named procedures. It returns carry clear when its operation is completed
  129. ; for normal actions and carry set when Connect mode must be exited. When
  130. ; Connect mode is exited the just read char should be passed in Kbdflg
  131. ; to msster.asm for invoking actions such as Status, send a break,
  132. ; quit connect mode; system dependent procedure Term is responsible for this.
  133. ;
  134. ;  Principal procedures are -
  135. ;       msuinit         Initializes keyboard translator in this file when
  136. ;                       Kermit first begins. Installs dfkey and shkey as the
  137. ;                       procedures used for Set Key and Show Key. Sys Indep.
  138. ;                       Called from msx or msy init procs. System Independent.
  139. ;       keybd           Performs the translation, outputs chars to the serial
  140. ;                       port or invokes a Kermit action routine. Sys Indep.
  141. ;       dfkey           Defines a key's translation. Reads command line
  142. ;                       via Kermit's command parser comnd. System Independent.
  143. ;       shkey           Shows translation of a key. Requests user to push
  144. ;                       selected key. System Independent.
  145. ;
  146. ;       kbdinit         optional. Initializes the translation tables when
  147. ;                       Kermit starts up. Called by msuinit. System Dependent.
  148. ;       getkey          Performs the keyboard read and returns results in
  149. ;                       a standardized system independent format. Sys Depend.
  150. ;       postkey         called by active translator after obtaining a keycode.
  151. ;                       Used to provide extra local actions (keyclick) only
  152. ;                       in Connect mode (not during Set/Show key commands).
  153. ;                       Called by keybd. System dependent.
  154. ; Supporting system independent procedures are -
  155. ; shkfre (show string free space), tstkeyw (finds user's keyword in the verb
  156. ; table), insertst (insert string in buffer), remstr (delete string in buffer).
  157. ;
  158. ;   System dependent procedure Getkey reads a keycode (usually via a Bios
  159. ; call). On IBM compatible machines this yields <ah=scan code, al=ascii>
  160. ; for ordinary keys, or <ah=scan code, al=0> for special keys such as F1,
  161. ; or <ah=0, al=###> when Alt### is used.
  162. ; For any system, the canonical output form is the key's code in Keycode.
  163. ; Place the ascii code (or scan code if none) in byte Keycode and ancillary
  164. ; info (shift states plus marker bit for scan codes) in byte Keycode + 1.
  165. ;
  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                 ; 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:datas, es:datas
  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 datas 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,cmfile               ; parse a word
  469.         call    comnd                   ; get key code or original ascii char
  470.          nop
  471.          nop
  472.          nop
  473.         mov     al,intake               ; reading from Take file indirectly
  474.         or      al,taklev               ; ditto, directly
  475.         mov     msutake,al              ; save here
  476.         or      ah,ah                   ; any text given?
  477.         jnz     dfkey12                 ; nz = yes, so don't consider prompts
  478.                                         ; interactive key request
  479.         cmp     intake,0                ; in a Take file?
  480.         je      dfkey10                 ; e = no, prompt for keystroke
  481.         jmp     dfkey0                  ;  else say bad syntax
  482. dfkey10:mov     ah,prstr
  483.         mov     dx,offset dfaskky       ; ask for key to be pressed
  484.         int     dos
  485. dfkey11:call    getkey                  ; read key ident from keyboard
  486.         jc      dfkey11                 ; c = no response, wait for keystroke
  487.         mov     ah,prstr                ; display cr/lf
  488.         mov     dx,offset crlf
  489.         int     dos
  490.         call    shkey0                  ; show current definition (in SHKEY)
  491.         jmp     dfkey1e                 ; prompt for and process definition
  492.  
  493. dfkey12:                                ; Look for word SCAN and ignore it
  494.         mov     dx,word ptr tranbuf     ; get first two characters
  495.         or      dx,2020h                ; map upper to lower case
  496.         cmp     dx,'cs'                 ; first two letters of word "scan"?
  497.         je      dfkey                   ; e = yes, skip the word
  498.         cmp     dx,'lc'                 ; first two letters of word "clear"?
  499.         je      dfkeyc                  ; e = yes, reinit keyboard
  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. dfkey0: mov     dx,offset dfhelp1       ; say bad definition command
  507.         mov     ah,prstr
  508.         int     dos
  509.         jmp     rskp
  510.  
  511. dfkeyc:                                 ; CLEAR key defs, restore startup defs
  512.         mov     cx,maxkeys              ; size of keycode tables
  513.         push    es                      ; save register
  514.         push    ds
  515.         pop     es                      ; make es point to datas segment
  516.         mov     ax,0                    ; null, value to be stored
  517.         mov     di,offset dirlist       ; director table
  518.         cld
  519.         rep     stosw                   ; clear it
  520.         mov     cx,maxkeys
  521.         mov     di,offset keylist       ; keycode table
  522.         rep     stosw                   ; clear it
  523.         mov     cx,maxstng
  524.         mov     di,offset sptable       ; string pointer table
  525.         rep     stosw                   ; clear it
  526.         pop     es                      ; recover register
  527.         mov     strmax,offset stbuf     ; clear string buffer
  528.         mov     stbuf,0                 ;
  529.         mov     nkeys,0                 ; clear number of defined keys
  530.         call    msuinit                 ; restore startup definitions
  531.         jmp     rskp
  532.                                         ; Multi-char key identification
  533. dfkey1: mov     si,offset tranbuf       ; point to key ident text
  534.         cmp     byte ptr [si],'0'       ; is first character numeric?
  535.         jb      dfkey1a                 ; b = no
  536.         cmp     byte ptr [si],'9'       ; in numbers?
  537.         ja      dfkey1a                 ; a = no
  538.         mov     keycode,scan            ; setup keycode for scan value
  539.         mov     dx,si                   ; get length of string in cx
  540.         call    strlen
  541.         push    ds
  542.         pop     es                      ; make es point to datas segment
  543.         push    si
  544.         add     si,cx                   ; point at string terminator
  545.         mov     di,si
  546.         inc     di                      ; place to store string (1 byte later)
  547.         inc     cx                      ; include null terminator
  548.         std                             ; work backward
  549.         rep     movsb                   ; move string one place later
  550.         cld
  551.         pop     si
  552.         mov     byte ptr [si],'\'       ; make ascii digits into \nnn form
  553.         mov     oldform,0ffh            ; set old form flag
  554.         mov     dx,offset kwarnmsg      ; tell user this is old form
  555.         mov     ah,prstr
  556.         int     dos
  557. dfkey1a:call    katoi                   ; convert ascii number to binary in ax
  558.         jc      dfkey0                  ; c = no number converted
  559.         or      keycode,ax              ; store in keycode
  560.  
  561. dfkey1b:                                ; Get Definition proper
  562.         test    oldform,0ffh            ; old form Set Key active?
  563.         jz      dfkey1f                 ; z = no
  564.         mov     bx,offset tranbuf       ; get new definition on main cmd line
  565.         mov     word ptr [bx],0         ; insert terminator
  566.         mov     dx,offset dfhelp2       ; help for definition of key
  567.         mov     ah,cmtxt                ; read rest of line into tranbuf
  568.         call    comnd
  569.          nop                            ; allow null definitions
  570.          nop
  571.          nop
  572.         or      ah,ah                   ; char count zero?
  573.         jz      dfkey1e                 ; z = zero, prompt for definition
  574.         jmp     dfkey1g                 ; process definition
  575.  
  576. dfkey1e:mov     ah,prstr
  577.         mov     dx,offset crlf
  578.         int     dos
  579.         mov     dx,offset dfaskdf       ; prompt for definition string
  580.         call    prompt                  ; Kermit prompt routine
  581.         mov     comand.cmcr,1           ; permit bare carriage returns
  582. dfkey1f:mov     bx,offset tranbuf       ; get new definition
  583.         mov     word ptr [bx],0         ; insert terminator
  584.         mov     dx,offset dfhelp2       ; help for definition of key
  585.         mov     ah,cmtxt                ; read rest of line into tranbuf
  586.         call    comnd
  587.          jmp r                          ; exit now on ^C from user
  588.          nop
  589.         cmp     comand.cmcr,0           ; prompting for definition?
  590.         je      dfkey1g                 ; e = no, trim leading whitespace
  591.         mov     comand.cmcr,0           ; turn off allowance for bare c/r's
  592.         jmp     dfkey2                  ; interactive, allow leading whitespace
  593. dfkey1g:xchg    ah,al                   ; put byte count in al
  594.         xor     ah,ah                   ; clear high byte
  595.         mov     kbtemp,ax               ; and save count in kbtemp
  596.         mov     ah,cmcfm                ; get a confirm
  597.         call    comnd
  598.          jmp    r                       ; none so declare parse error
  599.          nop                            ; round out to three bytes
  600.         mov     cx,kbtemp               ; string length
  601.         jcxz    dfkey2                  ; z = empty string
  602.         push    si
  603.         push    di
  604.         mov     si,offset tranbuf       ; strip leading white space
  605. dfkey1c:cld                             ; work forward
  606.         lodsb                           ; read string char into al
  607.         dec     cx                      ; number of chars left to read
  608.         cmp     al,' '                  ; a space?
  609.         je      dfkey1c                 ; e = yes, keep going
  610.         cmp     al,tab                  ; tab?
  611.         je      dfkey1c                 ; e = yes, keep going
  612.         dec     si                      ; offset inc si in lodsb
  613.         add     cx,2                    ; include terminator, offset dec above
  614.         jcxz    dfkey1d                 ; z = nothing to move
  615.         mov     di,offset tranbuf       ; destination is start of buffer
  616.         push    ds
  617.         pop     es
  618.         cld
  619.         rep     movsb                   ; copy text part of string
  620. dfkey1d:pop     di
  621.         pop     si
  622.  
  623. dfkey2:                                 ; Examine translation
  624.         mov     al,trans.escchr         ; current escape char (port dependent)
  625.         cmp     al,byte ptr keycode     ; is this Kermit's escape char?
  626.         jne     dfkey2a                 ; ne = no
  627.         test    keycode,scan            ; see if scan code
  628.         jnz     dfkey2a                 ; nz = scan, so not ascii esc char
  629.         mov     dx,offset dfkopps       ; Opps! msg
  630.         mov     ah,prstr                ; complain and don't redefine
  631.         int     dos
  632.         jmp     rskp
  633.  
  634. dfkey2a:push    di                      ; get a director code for this key
  635.         push    cx
  636.         mov     di,offset keylist       ; list of keycodes
  637.         mov     cx,nkeys                ; number currently defined
  638.         mov     ax,keycode              ; present keycode
  639.         jcxz    dfkey2b                 ; cx = 0 means none defined yet
  640.         cld
  641.         push    ds
  642.         pop     es
  643.         repne   scasw                   ; is current keycode in the list?
  644.         jne     dfkey2b                 ; ne = not in list
  645.         sub     di,2                    ; correct for auto increment
  646.         sub     di,offset keylist
  647.         mov     listptr,di              ; list pointer for existing definition
  648.         pop     cx
  649.         pop     di
  650.         jmp     dfkey3                  ; go process definition
  651.  
  652. dfkey2b:pop     cx                      ; key not currently defined so
  653.         pop     di                      ;  make a new director entry for it
  654.         mov     bx,nkeys                ; number of keys previously defined
  655.         cmp     bx,maxkeys              ; enough space?
  656.         jae     dfkey2c                 ; ae = no, complain
  657.         shl     bx,1                    ; count words
  658.         mov     listptr,bx              ; index into word list
  659.         mov     ax,keycode              ; get key's code
  660.         mov     keylist[bx],ax          ; store it in list of keycodes
  661.         mov     dirlist[bx],0           ; clear the new director entry
  662.         inc     nkeys                   ; new number of keys
  663.         jmp     dfkey3                  ; go process definition
  664.  
  665. dfkey2c:mov     dx,offset keyfull       ; say key space is full already
  666.         mov     ah,prstr
  667.         int     dos
  668.         jmp     rskp                    ; tell parser we are happy
  669. ; listptr has element number in keylist or dirlist; keycode has key's code.
  670.  
  671. ; Parse new definition. First look for Kermit verbs as a line beginning
  672. ; as \K or \{K. Otherwise, consider the line to be a string.
  673. ; In any case, update the Director table for the new definition.
  674.  
  675. dfkey3: mov     brace,0                 ; assume not using braces
  676.         mov     si,offset tranbuf       ; start of definition text
  677.         cmp     byte ptr [si],'\'       ; starts with escape char?
  678.         jne     dfkey5                  ; ne = no, so we have a string
  679.         inc     si                      ; skip the backslash
  680.         cmp     byte ptr [si],braceop   ; starts with \{?
  681.         jne     dfkey3a                 ; ne = no
  682.         inc     si                      ; skip the opening brace
  683.         mov     brace,bracecl           ; expect closing brace
  684. dfkey3a:cmp     byte ptr [si],'K'       ; starts with \{K or \K?
  685.         je      dfkey3b                 ; e = yes
  686.         cmp     byte ptr [si],'k'       ; starts as \{k or \k?
  687.         jne     dfkey5                  ; ne = no, then it's a string
  688. dfkey3b:inc     si                      ; yes, skip the K too
  689.                                         ; Kermit action VERBS
  690.         push    si                      ; save verb name start address
  691. dfkey4a:cld
  692.         lodsb                           ; scan til closing brace or w/s or end
  693.         cmp     al,0                    ; premature end?
  694.         je      dfkey4b                 ; e = yes, accept without brace
  695.         cmp     al,brace                ; closing brace?
  696.         je      dfkey4b                 ; e = yes
  697.         cmp     al,spc                  ; white space or control char?
  698.         ja      short dfkey4a           ; a = no, so not at end yet
  699. dfkey4b:mov     byte ptr[si-1],0        ; insert null terminator
  700.         pop     si                      ; recover start address
  701.         call    tstkeyw                 ; find keyword, kw # returned in kbtemp
  702.         jc      dfkey4d                 ; c = no keyword found, complain
  703.         call    remstr                  ; clear old string, if string
  704.         mov     ax,kbtemp               ; save keyword number
  705.         and     ax,not(verb+strng)      ; clear verb / string field
  706.         or      ax,verb                 ; set verb ident
  707.         mov     si,listptr
  708.         mov     dirlist[si],ax          ; store info in Director table
  709.         jmp     dfkey7                  ; show results and return success
  710.  
  711. dfkey4d:mov     dx,offset verbbad       ; say no such verb
  712.         mov     ah,prstr
  713.         int     dos
  714.         jmp     rskp
  715.  
  716. ; Here we are left with the definition string; si points to its start, and
  717. ; kbtemp holds its length (number of bytes). Null termination. If the string
  718. ; begins with an opening brace it terminates on a matching closing brace
  719. ; or the end of line, whichever occurs first. Trailing whitespace removed
  720. ; before examining braces.
  721. ; Null length strings mean define key as Self.
  722.                                         ; STRING definitions
  723. dfkey5: call    remstr                  ; first, clear old string, if any
  724.         mov     si,offset tranbuf       ; si=source, di=dest, convert in-place
  725.         mov     di,si
  726.         call    cnvlin                  ; convert numbers, cx gets line length
  727.         mov     si,offset tranbuf       ; provide address of new string
  728.         cmp     cx,1                    ; just zero or one byte to do?
  729.         jbe     dfkey6                  ; e = yes, do as a char
  730.         call    insertst                ; insert new string, returns reg cx.
  731.         jc      dfkey5h                 ; c = could not do insert
  732.         mov     si,listptr              ; cx has type and string number
  733.         mov     dirlist[si],cx          ; update Director table from insertst
  734.         jmp     dfkey7                  ; show results and return success
  735.  
  736. dfkey5h:mov     dx,offset strbad        ; display complaint
  737.         mov     ah,prstr
  738.         int     dos
  739. dfkeyx: jmp     rskp
  740.  
  741.                 ; define SINGLE CHAR replacement or CLEAR a key definition.
  742.                 ; cx has char count 1 (normal) or 0 (to undefine the key).
  743. dfkey6: jcxz    dfkey6c                 ; z = cx= 0, clear definition
  744.         mov     al,byte ptr [si]        ; get first byte from definition
  745.         xor     ah,ah                   ; set the type bits to Char
  746.         mov     si,listptr
  747.         mov     dirlist[si],ax          ; store type and key's new code
  748.         jmp     dfkey7                  ; return success
  749.  
  750. dfkey6c:push    si                      ; clear a definition,
  751.         push    di                      ; listptr points to current def
  752.         mov     si,listptr              ; starting address to clear
  753.         add     si,offset dirlist
  754.         mov     di,si                   ; destination
  755.         add     si,2                    ; source is next word
  756.         mov     cx,nkeys                ; current number of keys defined
  757.         add     cx,cx                   ; double for listptr being words
  758.         sub     cx,listptr              ; cx = number of words to move
  759.         shr     cx,1                    ; convert to actual number of moves
  760.         jcxz    dfkey6d                 ; z = none, just remove last word
  761.         push    es
  762.         push    ds
  763.         pop     es                      ; make es:di point to datas segment
  764.         cld
  765.         push    cx                      ; save cx
  766.         rep     movsw                   ; move down higher list items
  767.         pop     cx
  768.         mov     si,listptr              ; do keylist too, same way
  769.         add     si,offset keylist
  770.         mov     di,si
  771.         add     si,2
  772.         rep     movsw
  773.         pop     es
  774. dfkey6d:mov     si,nkeys                ; clear old highest list element
  775.         shl     si,1                    ; address words
  776.         mov     dirlist[si],0           ; null the element
  777.         mov     keylist[si],0           ; null the element
  778.         dec     nkeys                   ; say one less key defined now
  779.         pop     di                      ; restore saved registers
  780.         pop     si
  781.  
  782. dfkey7: mov     ah,msutake              ; Finish up. In a Take file?
  783.         or      ah,taklev               ; or even directly
  784.         cmp     ah,0
  785.         je      dfkey7a                 ; e = no
  786.         cmp     flags.takflg,0          ; echo Take commands?
  787.         je      dfkey7b                 ; e = no
  788. dfkey7a:mov     ah,prstr                ; display cr/lf
  789.         mov     dx,offset crlf
  790.         int     dos
  791.         call    shkey0                  ; show new definition (in SHKEY)
  792.         call    shkfre                  ; show free string space
  793. dfkey7b:jmp     rskp                    ; return success
  794. DFKEY   ENDP
  795.  
  796. ; SHOW KEY <cr> command. Call from Kermit level. Vectored here by SHOW
  797. ; command. Replaces obsolete procedure in msx---.
  798. ; Prompts for a key and shows that key's (or all if ? entered) keycode,
  799. ; definition, and the key definition free space remaining.
  800.  
  801. SHKEY   PROC    NEAR                    ; Show key's definition command
  802.         mov     ah,cmcfm                ; get a confirm
  803.         call    comnd
  804.          nop                            ; ignore any additional text
  805.          nop
  806.          nop
  807.         push    bx
  808.         mov     dx,offset shkmsg1       ; ask for original key
  809.         mov     ah,prstr
  810.         int     dos
  811. shky0:  call    getkey                  ; read keyboard, output to keycode
  812.         jc      shky0                   ; wait for a key (c = nothing there)
  813.         cmp     byte ptr keycode,'?'    ; query for all keys?
  814.         jne     shky0a                  ; ne = no, not a query
  815.         test    keycode,scan            ; is this a scan code, vs ascii query?
  816.         jz      shky0c                  ; z = no Scan, so it is a query
  817.  
  818. shky0a: mov     ah,prstr                ; show single key. Setup display
  819.         mov     dx,offset crlf
  820.         int     dos
  821.         call    shkey0                  ; show just one key
  822. shky0b: call    shkfre                  ; show free string space
  823.         jmp     shkeyx                  ; exit
  824.  
  825. shky0c: mov     cx,nkeys                ; Show all keys. nkeys = number defined
  826.         jcxz    shky0b                  ; z = none to show
  827.         mov     si,offset keylist       ; list of definitions
  828.         push    si                      ; save pointer
  829. shky1:  pop     si                      ; recover pointer
  830.         cld
  831.         lodsw                           ; get a keycode
  832.         push    si                      ; save pointer
  833.         push    cx                      ; save counter
  834.         mov     keycode,ax              ; save new keycode
  835.         mov     ah,prstr
  836.         mov     dx,offset crlf
  837.         int     dos
  838.         call    shkey0                  ; show this keycode
  839.  
  840.         pop     cx                      ; pause between screens, recover cntr
  841.         push    cx                      ; save it again
  842.         dec     cx                      ; number yet to be shown
  843.         jcxz    shky1b                  ; z = have now shown all of them
  844.         mov     ax,nkeys                ; number of defined keys
  845.         sub     ax,cx                   ; minus number yet to be displayed
  846.         xor     dx,dx                   ; clear extended numerator
  847.         div     twelve                  ; two lines per definition display
  848.         or      dx,dx                   ; remainder zero (12 defs shown)?
  849.         jnz     shky1b                  ; nz = no, not yet so keep going
  850.         mov     ah,prstr
  851.         mov     dx,offset shkmsg3       ; "push any key to continue" msg
  852.         int     dos
  853. shky1a: call    getkey                  ; get any key
  854.         jc      shky1a                  ; c = nothing at keyboard yet, wait
  855. shky1b: pop     cx                      ; resume loop
  856.         loop    shky1
  857.         pop     si                      ; clean stack
  858.         call    shkfre                  ; show free string space
  859.         jmp     shkeyx                  ; exit
  860.  
  861.                 ; show key worker routine, called from above
  862.                                         ; SHKEY0 called by DFKEY just above
  863. SHKEY0: test    keycode,scan            ; scan code?
  864.         jz      shkey1                  ; z = no, regular ascii
  865.  
  866.                                         ; SCAN codes
  867.         mov     dx,offset scanmsg       ; say Scan Code:
  868.         mov     ah,prstr
  869.         int     dos
  870.         mov     ah,conout
  871.         mov     dl,'\'                  ; add backslash before number
  872.         int     dos
  873.         mov     ax,keycode              ; get key's code again
  874.         call    decout                  ; display 16 bit decimal keycode
  875.         jmp     shkey2                  ; go get definition
  876.  
  877. shkey1: mov     dx,offset ascmsg        ; say ASCII CHAR
  878.         mov     ah,prstr
  879.         int     dos
  880.         mov     dl,byte ptr keycode     ; get ascii code (al part of input)
  881.         mov     ah,conout
  882.         cmp     dl,spc                  ; control code?
  883.         jae     shkey1a                 ; ae = no
  884.         push    dx                      ; save char
  885.         mov     dl,5eh                  ; show caret first
  886.         int     dos
  887.         pop     dx
  888.         add     dl,'A'-1                ; ascii bias
  889. shkey1a:cmp     dl,del                  ; DEL?
  890.         jne     shkey1b                 ; ne = no
  891.         mov     dl,'D'                  ; spell out DEL
  892.         int     dos
  893.         mov     dl,'E'
  894.         int     dos
  895.         mov     dl,'L'
  896. shkey1b:int     dos
  897.         mov     dl,spc                  ; add a couple of spaces
  898.         int     dos
  899.         int     dos
  900.         mov     dl,'\'                  ; add backslash before number
  901.         int     dos
  902.         mov     ax,keycode              ; show 16 bit keycode in decimal
  903.         call    decout                  ; and go get definiton
  904.  
  905.                                         ; Display defintion
  906. shkey2: mov     dx,offset shkmsg2       ; intermediate part of reply
  907.         mov     ah,prstr                ; " is defined as "
  908.         int     dos
  909.         push    di                      ; get a director code for this key
  910.         push    cx
  911.         mov     di,offset keylist       ; list of keycodes
  912.         mov     cx,nkeys                ; number currently defined
  913.         jcxz    shkey2a                 ; z = none
  914.         mov     ax,keycode              ; present keycode
  915.         push    ds
  916.         pop     es                      ; use datas segment for es:di
  917.         cld
  918.         repne   scasw                   ; is current keycode in the list?
  919.         jne     shkey2a                 ; ne = not in list
  920.         sub     di,2                    ; correct for auto increment
  921.         sub     di,offset keylist
  922.         mov     listptr,di              ; list pointer for existing definition
  923.         pop     cx
  924.         pop     di
  925.         jmp     shkey3                  ; go process definition
  926.  
  927. shkey2a:pop     cx
  928.         pop     di
  929.         mov     dx,offset noxmsg        ; say Self (no translation)
  930.         mov     ah,prstr
  931.         int     dos
  932.         ret                             ; return to main show key loop
  933.  
  934. shkey3:                                 ; translations, get kind of.
  935.         mov     si,listptr
  936.         test    dirlist[si],verb        ; defined as verb?
  937.         jnz     shkey6                  ; nz = yes, go do that one
  938.         test    dirlist[si],strng       ; defined as string?
  939.         jz      shkey3a                 ; z = no
  940.         jmp     shkey8                  ; yes, do string display
  941. shkey3a:
  942.         mov     dx,offset ascmsg        ; CHAR. say 'Ascii char:'
  943.         mov     ah,prstr
  944.         int     dos
  945.         mov     ax,dirlist [si]         ; get type and char
  946.         mov     dl,al                   ; put char here for display
  947.         push    ax                      ; save here too
  948.         mov     ah,conout
  949.         cmp     dl,spc                  ; control code?
  950.         jae     shkey4                  ; ae = no
  951.         push    dx
  952.         mov     dl,5eh                  ; show caret
  953.         int     dos
  954.         pop     dx
  955.         add     dl,'A'-1                ; add ascii bias
  956. shkey4: cmp     dl,del                  ; DEL?
  957.         jne     shkey4a                 ; ne = no
  958.         mov     dl,'D'                  ; spell out DEL
  959.         int     dos
  960.         mov     dl,'E'
  961.         int     dos
  962.         mov     dl,'L'
  963. shkey4a:int     dos
  964.         mov     dl,spc                  ; add a couple of spaces
  965.         mov     ah,conout
  966.         int     dos
  967.         int     dos
  968.         mov     dl,'\'                  ; add backslash before number
  969.         int     dos
  970.         pop     ax                      ; recover char
  971.         xor     ah,ah                   ; clear high byte
  972.         call    decout                  ; show decimal value
  973.         ret                             ; return to main show key loop
  974.  
  975. shkey6: mov     ah,prstr                ; VERB
  976.         mov     dx,offset verbmsg       ; say 'verb'
  977.         int     dos
  978.         mov     si,listptr              ; get verb index from director
  979.         mov     dx,dirlist[si]
  980.         and     dx,not(verb+strng)      ; remove type bits, leaves verb number
  981.         mov     bx,offset kverbs        ; table of verbs & actions
  982.         mov     al,byte ptr [bx]        ; number of keywords
  983.         xor     ah,ah
  984.         dec     ax
  985.         mov     kwcnt,ax                ; save number of last one here
  986.         cmp     dx,ax                   ; asking for more than we have?
  987.         ja      shkeyx                  ; a = yes, exit bad
  988.         inc     bx                      ; point to first slot
  989.         mov     cx,0                    ; current slot number
  990. shkey6b:cmp     cx,dx                   ; this slot?
  991.         je      shkey6c                 ; e = yes, print the text part
  992.         ja      shkeyx                  ; a = beyond, exit bad
  993.         mov     al,byte ptr [bx]        ; get cnt (keyword length)
  994.         xor     ah,ah
  995.         add     ax,4                    ; skip over '$' and two byte value
  996.         add     bx,ax                   ; bx = start of next keyword slot
  997.         inc     cx                      ; current keyword number
  998.         jmp     short shkey6b           ; try another
  999. shkey6c:inc     bx                      ; look at text field
  1000.         mov     dx,bx                   ; offset for printing
  1001.         mov     ah,prstr
  1002.         int     dos
  1003.         mov     ah,conout
  1004.         mov     dl,spc                  ; add a couple of spaces
  1005.         int     dos
  1006.         int     dos
  1007.         mov     dl,'\'                  ; show verb name as \Kverb
  1008.         int     dos
  1009.         mov     dl,'K'
  1010.         int     dos
  1011.         mov     ah,prstr
  1012.         mov     dx,bx                   ; show name part again
  1013.         int     dos
  1014.         ret                             ; return to main show key loop
  1015.  
  1016. shkey8: mov     ah,prstr                ; STRING
  1017.         mov     dx,offset strngmsg      ; say String:
  1018.         int     dos
  1019.         mov     si,listptr              ; get index from director
  1020.         mov     bx,dirlist[si]
  1021.         and     bx,not(verb+strng)      ; remove type bits
  1022.         shl     bx,1                    ; index words
  1023.         mov     si,sptable[bx]          ; table of string offsets
  1024.         mov     cl,byte ptr [si]        ; get string length byte
  1025.         xor     ch,ch
  1026.         inc     si                      ; point to string text
  1027.         mov     ah,conout
  1028. shkey8a:cld
  1029.         lodsb                           ; get a byte
  1030.         cmp     al,spc                  ; control code?
  1031.         jae     shkey8b                 ; ae = no
  1032.         push    ax
  1033.         mov     dl,5eh                  ; show caret first
  1034.         int     dos
  1035.         pop     ax
  1036.         add     al,40h                  ; convert to printable for display
  1037. shkey8b:mov     dl,al
  1038.         int     dos                     ; display it
  1039.         loop    shkey8a                 ; do another
  1040.         ret                             ; return to main show key loop
  1041.  
  1042. shkeyx: pop     bx                      ; restore reg
  1043.         jmp     rskp                    ; return success
  1044. SHKEY   ENDP
  1045.  
  1046. ;;;     keyboard translator local support procedures, system independent
  1047.  
  1048. ; Tstkeyw checks text word pointed to by si against table of keywords (pointed
  1049. ; to by kverbs, made by mkeyw macro); returns in bx either action value or 0.
  1050. ; Returns in kbtemp the number of the keyword and carry clear, or if failure
  1051. ; returns kbtemp zero and carry set.
  1052. ; Keyword structure is:         db      cnt     (length of string 'word')
  1053. ;                               db      'word'  (keyword string)
  1054. ;                               db      '$'     (printing terminator)
  1055. ;                               dw      value   (value returned in bx)
  1056. ; Make these with macro mkeyw such as   mkeyw 'test',15   with the list of
  1057. ; such keywords headed by a byte giving the number of keywords in the list.
  1058. tstkeyw proc    near
  1059.         push    ax
  1060.         push    cx
  1061.         push    si
  1062.         mov     verblen,0               ; verblen will hold verb length
  1063.         push    si                      ; save user's verb pointer
  1064. tstkw1: cld
  1065.         lodsb                           ; get a verb character
  1066.         cmp     al,spc                  ; verbs are all non-spaces and above
  1067.         jbe     tstkw2                  ; be = done (space or control char)
  1068.         inc     verblen                 ; count verb length
  1069.         jmp     short tstkw1            ; printable char, look for more
  1070. tstkw2: pop     si                      ; pointer to verb
  1071.         mov     bx,offset kverbs        ; table of Kermit verb keywords
  1072.         mov     al,byte ptr [bx]        ; number of keywords
  1073.         xor     ah,ah
  1074.         mov     kwcnt,ax                ; save number of keywords here
  1075.         inc     bx                      ; point bx to first slot
  1076.         mov     kbtemp,0                ; remember which keyword
  1077.  
  1078. tstkw3:                                 ; match table keyword and text word
  1079.         mov     cx,verblen              ; length of user's verb
  1080.         cmp     byte ptr [bx],cl        ; compare length vs table keyword
  1081.         jne     tstkw4                  ; ne = not equal lengths, try another
  1082.         push    si                      ; lengths match, how about spelling?
  1083.         push    bx
  1084.         inc     bx                      ; point at start of keyword
  1085. tstkw3a:mov     ah,byte ptr [bx]        ; keyword char
  1086.         mov     al,byte ptr [si]        ; text char
  1087.         cmp     ah,'A'
  1088.         jb      tstkw3b                 ; b = control chars
  1089.         cmp     ah,'Z'
  1090.         ja      tstkw3b                 ; a = not upper case alpha
  1091.         add     ah,'a'-'A'              ; convert upper case to lower case
  1092. tstkw3b:cmp     al,'A'
  1093.         jb      tstkw3c
  1094.         cmp     al,'Z'
  1095.         ja      tstkw3c
  1096.         add     al,'a'-'A'              ; convert upper case to lower case
  1097. tstkw3c:cmp     al,ah                   ; test characters
  1098.         jne     tstkw3d                 ; ne = no match
  1099.         inc     si                      ; move to next char
  1100.         inc     bx
  1101.         loop    tstkw3a                 ; loop through entire length
  1102. tstkw3d:pop     bx
  1103.         pop     si
  1104.         jcxz    tstkw5                  ; z: cx = 0, exit with match;
  1105.                                         ;  else select next keyword
  1106. tstkw4: inc     kbtemp                  ; number of keyword to test next
  1107.         mov     cx,kbtemp
  1108.         cmp     cx,kwcnt                ; all done? Recall kbtemp starts at 0
  1109.         jae     tstkwx                  ;ae = exhausted search, unsuccessfully
  1110.         mov     al,byte ptr [bx]        ; cnt (keyword length from macro)
  1111.         xor     ah,ah
  1112.         add     ax,4                    ; skip over '$' and two byte value
  1113.         add     bx,ax                   ; bx = start of next keyword slot
  1114.         jmp     tstkw3                  ; do another comparison
  1115.  
  1116. tstkw5:                                 ; get action pointer
  1117.         mov     al,byte ptr [bx]        ; cnt (keyword length from macro)
  1118.         xor     ah,ah
  1119.         add     ax,2                    ; skip over '$'
  1120.         add     bx,ax                   ; now bx points to dispatch value
  1121.         mov     bx,[bx]                 ; bx holds dispatch value
  1122.         clc                             ; carry clear for success
  1123.         jmp     short tstkwxx           ; exit
  1124.         ret
  1125. tstkwx: xor     bx,bx                   ; exit when no match
  1126.         mov     kbtemp,bx               ; make verb number be zero too
  1127.         stc                             ; carry set for failure
  1128. tstkwxx:pop     si
  1129.         pop     cx
  1130.         pop     ax
  1131.         ret
  1132. tstkeyw endp
  1133.  
  1134. ; Insert asciiz string pointed to by si into string buffer stbuf.
  1135. ; Reg cx has string length upon entry.
  1136. ; Success: returns offset of first free byte (strmax) in string buffer stbuf,
  1137. ; cx = type and Index of new string, and carry clear.
  1138. ; Failure = carry set.
  1139. insertst proc   near
  1140.         push    bx
  1141.         push    dx
  1142.         push    si
  1143.         push    di
  1144.         push    kbtemp          ; save this variable too
  1145.         mov     dx,cx           ; save length of incoming string in dx
  1146.         mov     bx,offset sptable ; table of string offsets
  1147.         mov     kbtemp,0        ; slot number
  1148.         mov     cx,maxstng      ; number of entries, find an empty slot
  1149. insert1:cmp     word ptr[bx],0  ; slot empty?
  1150.         je      insert2         ; e = yes
  1151.         inc     kbtemp          ; remember slot number
  1152.         add     bx,2            ; look at next slot
  1153.         loop    insert1         ; keep looking
  1154.         jmp     short insert4   ; get here if no empty slots
  1155. insert2:                        ; see if stbuf has sufficient space
  1156.         mov     cx,dx           ; length of new string to cx
  1157.         mov     di,strmax       ; offset of first free byte in stbuf
  1158.         add     di,cx           ; di = address where this string would end
  1159.         cmp     di,offset stbuf+stbuflen ; beyond end of buffer?
  1160.         jae     insert4         ; ae = yes, not enough room
  1161.         mov     di,strmax       ; point to first free slot in stbuf
  1162.         mov     [bx],di         ; fill slot with address offset of buffer
  1163.         push    es
  1164.         push    ds
  1165.         pop     es              ; point es:di to datas segment
  1166.         cld
  1167.         mov     byte ptr [di],cl ; length of text for new string
  1168.         inc     di              ; move to next storage slot
  1169.         rep     movsb           ; copy string text
  1170.         pop     es
  1171.         mov     strmax,di       ; offset of next free byte
  1172.         mov     cx,kbtemp       ; return new slot number with Director Index
  1173.         and     cx,not(strng+verb) ; clear type bits
  1174.         or      cx,strng        ; say type is multi-char string
  1175.         clc                     ; say success
  1176.         jmp     short insertx   ; exit
  1177. insert4:stc                     ; say no-can-do
  1178. insertx:pop     kbtemp
  1179.         pop     di
  1180.         pop     si
  1181.         pop     dx
  1182.         pop     bx
  1183.         ret
  1184. insertst endp
  1185.  
  1186. ; Remove (delete) string. Enter with listptr preset for director entry.
  1187. ; Acts only on existing multi-char strings; recovers freed space.
  1188. ; All registers preserved.
  1189. remstr  proc    near
  1190.         push    si
  1191.         mov     si,listptr              ; list pointer
  1192.         test    dirlist[si],strng       ; multi-char string?
  1193.         pop     si
  1194.         jnz     remst1                  ; nz = a multi-char string
  1195.         ret                             ; else do nothing
  1196. remst1: push    ax
  1197.         push    bx
  1198.         push    cx
  1199.         push    dx
  1200.         push    si
  1201.         mov     si,listptr
  1202.         mov     ax,dirlist[si]          ; Director table entry
  1203.         and     ax,not(strng+verb) ; clear type bits, leave string's pointer
  1204.         mov     dirlist[si],0           ; clear Director table entry
  1205.         shl     ax,1                    ; index words not bytes
  1206.         mov     si,offset sptable       ; list of string offsets in stbuf
  1207.         add     si,ax                   ; plus index = current slot
  1208.         mov     bx,[si]                 ; get offset of string to be deleted
  1209.         mov     dx,bx                   ; save in dx for later
  1210.         mov     cl,byte ptr [bx]        ; get length byte
  1211.         xor     ch,ch                   ; get length of subject string
  1212.         inc     cx                      ; length byte too, cx has whole length
  1213.         sub     strmax,cx       ; count space to be freed (adj end-of-buf ptr)
  1214.         mov     word ptr [si],0 ; clear sptable of subject string address
  1215.         push    cx                      ; save length of purged string
  1216.         push    di                      ; save di
  1217.         push    si
  1218.         push    es                      ; save es
  1219.         push    ds
  1220.         pop     es              ; setup es:di to be ds:offset of string
  1221.         mov     di,dx           ; destination = start address of purged string
  1222.         mov     si,dx           ; source = start address of purged string
  1223.         add     si,cx           ;  plus string length of purged string.
  1224.         mov     cx,offset stbuf+stbuflen ; 1 + address of buffer end
  1225.         sub     cx,si                   ; 1 + number of bytes to move
  1226.         dec     cx                      ; number of bytes to move
  1227.         jcxz    remst2                  ; z = none
  1228.         cld                             ; direction is forward
  1229.         rep     movsb                   ; move down preserved strings
  1230. remst2: pop     es                      ; restore regs
  1231.         pop     di
  1232.         pop     si
  1233.         pop     ax              ; recover length of purged string (was in cx)
  1234.         mov     bx,offset sptable       ; string pointer table
  1235.         mov     cx,maxstng              ; max mumber of entries
  1236. remst4: cmp     [bx],dx         ; does this entry occur before purged string?
  1237.         jbe     remst5          ; be = before or equal, so leave it alone
  1238.         sub     [bx],ax         ; recompute address (remove old string space)
  1239. remst5: add     bx,2                    ; look at next list entry
  1240.         loop    remst4                  ; do all entries in sptable
  1241.         pop     si
  1242.         pop     dx
  1243.         pop     cx
  1244.         pop     bx
  1245.         pop     ax
  1246.         ret
  1247. remstr  endp
  1248.  
  1249. shkfre  proc    near                    ; show free key & string defs & space
  1250.         push    ax                      ; preserves all registers.
  1251.         push    bx
  1252.         push    cx
  1253.         push    dx
  1254.         push    kbtemp
  1255.         mov     dx,offset fremsg
  1256.         mov     ah,prstr
  1257.         int     dos
  1258.         mov     ax,maxkeys              ; max number of key defs
  1259.         sub     ax,nkeys                ; number currently used
  1260.         call    decout                  ; show the value
  1261.         mov     ah,prstr
  1262.         mov     dx,offset kyfrdef       ; give key defs msg
  1263.         int     dos
  1264.         mov     bx,offset sptable       ; table of string pointers
  1265.         mov     cx,maxstng              ; number of pointers
  1266.         mov     kbtemp,0                ; number free
  1267. shkfr1: cmp     word ptr [bx],0         ; slot empty?
  1268.         jne     shkfr2                  ; ne = no
  1269.         inc     kbtemp                  ; count free defs
  1270. shkfr2: add     bx,2                    ; look at next slot
  1271.         loop    shkfr1                  ; do all of them
  1272.         mov     ax,kbtemp               ; number of free defs
  1273.         call    decout                  ; display
  1274.         mov     dx,offset stfrdef       ; say free string defs
  1275.         mov     ah,prstr
  1276.         int     dos
  1277.         mov     ax,offset stbuf+stbuflen ; 1 + last byte in stbuf
  1278.         sub     ax,strmax               ; offset of last free byte in stbuf
  1279.         call    decout
  1280.         mov     dx,offset stfrspc       ; give free space part of msg
  1281.         mov     ah,prstr
  1282.         int     dos
  1283.         pop     kbtemp
  1284.         pop     dx
  1285.         pop     cx
  1286.         pop     bx
  1287.         pop     ax
  1288.         ret
  1289. shkfre  endp
  1290. ; Initialize the keyboard tables at Kermit startup time. Optional procedure.
  1291. ; Requires kbdinlst to be configured with mkeyw macro in the form
  1292. ;       mkeyw   'definition',keytype*256+keycode
  1293. ; keytype is 0 for scan codes and non-zero for ascii.
  1294. ; Returns normally.
  1295. kbdinit proc    near                    ; read keyword kbdinlst and setup
  1296.         push    ds                      ;  initial keyboard assignments.
  1297.         pop     es                      ; set es:di to datas segment
  1298.         mov     taklev,1                ; pretend that we are in Take file
  1299.         mov     si,offset kbdinlst      ; start of list of definitions
  1300. kbdini1:mov     cl,byte ptr [si]        ; cnt field (keyword length of macro)
  1301.         xor     ch,ch
  1302.         jcxz    kbdinix                 ; z = null cnt field = end of list
  1303.         inc     si                      ; look at text field
  1304.         mov     di,offset tranbuf       ; where defkey expects text
  1305.         cld
  1306.         rep     movsb                   ; copy cx chars to tranbuf
  1307.         mov     byte ptr [di],0         ; insert null terminator
  1308.         inc     si                      ; skip '$' field
  1309.         mov     ax,word ptr [si]        ; get value field
  1310.         mov     keycode,ax              ; set key ident value
  1311.         push    si
  1312.         call    dfkey2                  ; put dfkey to work
  1313.          nop
  1314.          nop
  1315.          nop
  1316.         pop     si
  1317.         add     si,2                    ; point to next entry
  1318.         jmp     kbdini1                 ; keep working
  1319. kbdinix:mov     taklev,0                ; reset Take file level
  1320.         ret
  1321. kbdinit endp
  1322. ;;;     End of System Independent Procedures
  1323.  
  1324. ;;;     Begin System Dependent Procedures
  1325.  
  1326. ; Read keyboard. System dependent.
  1327. ; Return carry set if nothing at keyboard.
  1328. ; If char present return carry clear with key's code in Keycode.
  1329. ; If key is ascii put that in the low byte of Keycode and clear bit Scan in
  1330. ; the high byte; otherwise, put the scan code in the lower byte and set bit
  1331. ; Scan in the high byte.
  1332. ; Bit Scan is set if key is not an ascii code.
  1333. ; Modifies register ax.
  1334. getkey  proc    near
  1335.         mov     keycode,0
  1336.         mov     ah,dconio               ; check console
  1337.         mov     dl,0ffh                 ; input desired
  1338.         int     dos
  1339.         jnz     getky1                  ; nz = char available
  1340.         stc                             ; carry set = nothing available
  1341.         jmp     short getkyx            ; exit on no char available
  1342. getky1: cmp     al,0                    ; scan code being returned?
  1343.         jne     getky1a                 ; ne = no
  1344.         mov     ah,dconio               ; read second byte (scan code)
  1345.         mov     dl,0ffh
  1346.         int     dos
  1347.         jz      getkyx                  ; z = nothing there
  1348.         mov     ah,al                   ; scan code goes here
  1349.         mov     al,0                    ; ascii code goes here
  1350. getky1a:
  1351.         push    di                      ; check key (ax) for aliases
  1352.         push    cx
  1353.         push    es
  1354.         mov     di,offset aliaskey      ; list of aliased keys
  1355.         mov     cx,aliaslen             ; number of entries
  1356.         jcxz    getky2                  ; z = no entries
  1357.         push    ds
  1358.         pop     es                      ; make es:di point to datas segment
  1359.         cld
  1360.         repne   scasw                   ; look for a match
  1361.         jne     getky2                  ; ne = not there
  1362.         mov     al,0                    ; force use of scan code (in ah)
  1363. getky2: pop     es
  1364.         pop     cx
  1365.         pop     di
  1366.         or      al,al                   ; scan code being returned?
  1367.         jnz     getky3                  ; nz = no
  1368.         xchg    ah,al                   ; put scan code in ident area
  1369.         or      keycode,scan            ; set scan flag (vs ascii)
  1370. getky3: mov     byte ptr keycode,al     ; return key's code (usually ascii)
  1371.         clc                             ; carry clear = got a char
  1372. getkyx: ret
  1373. getkey  endp
  1374.  
  1375.  
  1376. postkey proc    near                    ; do sys dep action after reading
  1377.         ret                             ; key during active translation
  1378. postkey endp
  1379.  
  1380. ; Jumping to this location is like retskp.  It assumes the instruction
  1381. ;   after the call is a jmp addr.
  1382.  
  1383. RSKP    PROC    NEAR
  1384.         pop bp
  1385.         add bp,3
  1386.         push bp
  1387.         ret
  1388. RSKP    ENDP
  1389.  
  1390. ; Jumping here is the same as a ret.
  1391.  
  1392. R       PROC    NEAR
  1393.         ret
  1394. R       ENDP
  1395.  
  1396. code    ends
  1397.         end
  1398.