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

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