home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / msugen.asm < prev    next >
Assembly Source File  |  2020-01-01  |  55KB  |  1,544 lines

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