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

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