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

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