home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / extra / nyenhuis3.arc / MSUIBM.ASM < prev    next >
Assembly Source File  |  1990-01-14  |  73KB  |  2,030 lines

  1.     NAME    msuibm
  2. ; File MSUIBM.ASM 
  3.     include mssdef.h
  4. ; Keyboard translator, by Joe R. Doupnik, Dec 1986
  5. ;  with contributions from David L. Knoell.
  6. ; edit history:
  7. ; Last edit 14 Jan 1990
  8. ; 7 Oct 1989 Add support for DEC LK250 keyboards, from Terry Kennedy.
  9. ; 2 August 1989 Allow verbs in definition strings [jrd]
  10. ; 21 Nov 1988 Version 2.32
  11. ; 12 Nov 1988 Add verbs terminalr and terminals, unassigned to keys.
  12. ; 1 July 1988 Version 2.31
  13. ; 20 May 1988 Add parser confirm requests below dfky13. [jrd]
  14. ; 10 March 1988 Add Holdscreen verb, holdscrn, for Terry Kennedy. [jrd]
  15. ; 27 Feb 1988 Add capability of stdin being a file rather than device. [jrd]
  16. ; 1 Jan 1988 version 2.30
  17.  
  18.     public    keybd, dfkey, shkey, msuinit, kbcodes
  19.     public    kbsusp, kbrest, kbhold        ;** LK250 support for IBM-PCs
  20.  
  21. ; some definitions
  22. kbint    equ    16h            ; IBM, Bios keyboard interrupt
  23. shift    equ    200h            ; IBM, synonym for right or left shift
  24. control    equ    400h            ; IBM, synonym for control shift
  25. alt    equ    800h            ; IBM, synonym for alt shift
  26. enhanced equ    1000h            ; IBM, enhanced keyboard code
  27.  
  28. rgt_shift equ    1            ; IBM shift state bits
  29. lft_shift equ    2
  30. ctl_shift equ    4
  31. alt_shift equ    8
  32. numlock      equ    20h
  33.  
  34. maxkeys    equ    200            ; maximum number of key definitions
  35. maxstng    equ    128            ; maximum number of multi-char strings
  36. stbuflen equ    1000            ; length of string buffer (bytes)
  37.  
  38. verb    equ    8000h            ; dirlist flag: use verb action table
  39. strng    equ    4000h            ; dirlist flag: use string action table
  40. scan    equ    100h            ; keycode flag: code is scan not ascii
  41. braceop    equ    7bh            ; opening curly brace
  42. bracecl    equ    7dh            ; closing curly brace
  43.  
  44. data    segment    public 'data'
  45.     extrn taklev:byte, comand:byte, flags:byte
  46.     extrn shkadr:word, stkadr:word, trans:byte, ttyact:byte
  47.                         ; system dependent references
  48.     extrn vtemu:byte, holdscr:byte        ; emulator data [jrd]
  49.     
  50. ;;;    System Independent local storage
  51.  
  52. tranbuf    db    132 dup (?)        ; 132 byte translator work buffer
  53. crlf    db    cr,lf,'$'
  54. dfhelp1    db    cr,lf,' Enter key',27h,'s identification as a character',cr,lf
  55.     db    '  or as its numerical equivalent \{b##} of ascii',cr,lf
  56.     db    '  or as its scan code \{b##}'
  57.     db    cr,lf,'  or as SCAN followed by its scan code',cr,lf
  58.     db    '    where b is O for octal, X for hex, or D for decimal'
  59.     db    ' (default).',cr,lf,'    Braces {} are optional.'
  60.     db    cr,lf,'    Follow the identification with the new definition.'
  61.     db    cr,lf,' or CLEAR to restore initial key settings'
  62.     db    cr,lf,' or ON (def) for Bios i/o or OFF to use DOS i/o.$' ;IBM
  63. dfaskky    db    cr,lf,' Push key to be defined: $'
  64. dfaskdf    db    ' Enter new definition: ',0        ; asciiz for prompt
  65. verbbad    db    cr,lf,' No such verb',cr,lf,'$'
  66. strbad    db    cr,lf,' Not enough space for new string',cr,lf,'$'
  67. keyfull    db    cr,lf,' No more space to define keys',cr,lf,'$'
  68. dfkoops    db    cr,lf,' Oops! That is Kermit',27h,'s Escape Char.'
  69.     db    ' Translation is not permitted.',cr,lf,'$'
  70. shkmsg1    db    cr,lf,'Push key to be shown (? shows all): $'
  71. shkmsg2    db    ' decimal is defined as',cr,lf,'$'
  72. shkmsg3    db    cr,lf,'... more, press a key to continue ...$'
  73. kwarnmsg db    cr,lf,' Notice: this form of Set Key is obsolete$'
  74.  
  75. ascmsg    db    ' Ascii char: $'
  76. scanmsg    db    ' Scan Code $'
  77. strngmsg db    ' String: $'
  78. verbmsg    db    ' Verb: $'
  79. noxmsg    db    ' Self, no translation.$'
  80. fremsg    db    cr,lf,' Free space: $'
  81. kyfrdef    db    ' key and $'
  82. stfrdef db    ' string definitions, $'
  83. stfrspc    db    ' string characters.',cr,lf,'$'
  84.                     ; translation tables
  85. keylist    dw    maxkeys dup (0)        ; 16 bit keycodes, paralled by dirlist
  86. dirlist    dw    maxkeys dup (0)        ; director {v+s} + {index | new char}
  87. sptable    dw    maxstng dup (0)        ; list of asciiz string offsets
  88. stbuf    dw    stbuflen dup (0)    ; buffer for strings
  89. strmax    dw    stbuf            ; first free byte in stbuf
  90. listptr    dw    ?            ; item number for keylist and dirlist
  91. nkeys    dw    0            ; number of actively defined keys
  92. keycode    dw    ?            ; ascii/scan code for key
  93. kbtemp    dw    ?            ; scratch storage for translator
  94. brace    db    ?            ; brace detected flag byte
  95. oldform    db    0            ; old form Set Key, if non-zero
  96. verblen    dw    ?            ; length of user's verb (work temp)
  97. kwcnt    dw    ?            ; number of keywords (work temp)
  98. msutake    db    ?            ; if being run from take file or not
  99. stringcnt dw    0            ; qty of string chars to be processed
  100. stringptr dw    0            ; address of next string char
  101. twelve    dw    12d
  102. dosflg    db    0
  103. ;;;    End System Independent Data Area
  104.  
  105. ;;;    System Dependent Data Area
  106. nrcptr    dw    0        ; pointer to code page to NRC table
  107. latinptr dw    0        ; pointer to code page to Latin1 table
  108. DECmnptr dw    0        ; pointer to code page to DEC-MCS table
  109. ;    edit dfhelp2 to include nice list of verbs for this system.
  110. dfhelp2 db    cr,lf,' Enter either  \Kverb  for a Kermit action verb',cr,lf
  111.     db    ' or a replacement string  (single byte binary numbers are'
  112.     db    ' \{b##})',cr,lf,' or push Return to undefine a key, ^C to'
  113.     db    ' retain current definition.'
  114.     db    cr,lf,' Braces {} are optional, and strings maybe enclosed in'
  115.     db    ' them.',cr,lf,' Strings may not begin with the character'
  116.     db    ' combinations of  \k  or  \{k',cr,lf
  117.     db    '    (start with a { brace instead).',cr,lf,lf
  118.     db    ' Verbs are as follows. VT320 keys (arrows and keypad):',cr,lf
  119.     db   '   uparr, dnarr, lfarr, rtarr, kpminus, kpcoma, kpdot, kpenter,'
  120.     db    cr,lf
  121.     db   '   Gold (same as PF1), PF1, PF2, PF3, PF4, kp0, ... kp9'
  122.     db    cr,lf,'   decFind, decInsert, decRemove, decSelect, decPrev,'
  123.     db    ' decNext'
  124.     db    cr,lf,'   User Definable Keys decF6, ...decF14, decHelp,'
  125.     db    ' decDO, decF17, ...decF20'
  126.     db    cr,lf,' Kermit screen control and actions:',cr,lf
  127.     db   '   upscn, dnscn, homscn, endscn, upone, dnone, prtscn, dump,'
  128.     db    cr,lf
  129.     db   '   logoff, logon, termtype, reset, holdscrn, modeline, break,'
  130.     db    ' lbreak, nethold,'
  131.     db    cr,lf
  132.     db   '   hangup, null (send one), terminalR, terminalS, DOS, help,'
  133.     db   ' status, exit'
  134.     db    cr,lf,'$'
  135.  
  136.     ; Aliaskey: keys having aliases - same ascii code but more than one
  137.     ; scan code, as on auxillary keypads. Use just scan codes with these.
  138.     ; Alternative use: force ascii keys to report out just scan codes.
  139.     ; Table format: high byte = scan code, low byte = ascii code. 
  140.     ; Contents are machine dependent.
  141. aliaskey dw    (14*scan)+bs        ; Backspace key [hi=scan, lo=ascii]
  142.     dw    (55*scan)+'*'        ; keypad asterisk
  143.     dw    (74*scan)+'-'        ; keypad minus
  144.     dw    (78*scan)+'+'        ; keypad plus
  145.     dw    (71*scan)+'7'        ; keypad numeric area
  146.     dw    (72*scan)+'8'
  147.     dw    (73*scan)+'9'
  148.     dw    (75*scan)+'4'
  149.     dw    (76*scan)+'5'
  150.     dw    (77*scan)+'6'
  151.     dw    (79*scan)+'1'
  152.     dw    (80*scan)+'2'
  153.     dw    (81*scan)+'3'
  154.     dw    (82*scan)+'0'
  155.     dw    (83*scan)+'.'
  156.     dw    (83*scan)+','        ; German keypad had comma vs dot
  157.     dw    (15*scan)+tab
  158.     dw    (28*scan)+cr        ; typewriter Enter key
  159. aliaslen equ    ($-aliaskey) shr 1    ; number of words in aliaskey table
  160.  
  161. kverbs    db    70            ; number of table entries below
  162.     mkeyw    'uparr',uparrw        ; independent of ordering and case!
  163.     mkeyw    'dnarr',dnarrw        ; mkeyw 'name',procedure entry point
  164.     mkeyw    'lfarr',lfarr
  165.     mkeyw    'rtarr',rtarr
  166.     mkeyw    'Gold',pf1
  167.     mkeyw    'PF1',pf1
  168.     mkeyw    'PF2',pf2
  169.     mkeyw    'PF3',pf3
  170.     mkeyw    'PF4',pf4
  171.     mkeyw    'KP0',kp0
  172.     mkeyw    'KP1',kp1
  173.     mkeyw    'KP2',kp2
  174.     mkeyw    'KP3',kp3
  175.     mkeyw    'KP4',kp4
  176.     mkeyw    'KP5',kp5
  177.     mkeyw    'KP6',kp6
  178.     mkeyw    'KP7',kp7
  179.     mkeyw    'KP8',kp8
  180.     mkeyw    'KP9',kp9
  181.     mkeyw    'kpminus',kpminus
  182.     mkeyw    'kpcoma',kpcoma
  183.     mkeyw    'kpenter',kpenter
  184.     mkeyw    'kpdot',kpdot
  185.     mkeyw    'decF6',decf6
  186.     mkeyw    'decF7',decf7
  187.     mkeyw    'decF8',decf8
  188.     mkeyw    'decF9',decf9
  189.     mkeyw    'decF10',decf10
  190.     mkeyw    'decF11',decf11
  191.     mkeyw    'decF12',decf12
  192.     mkeyw    'decF13',decf13
  193.     mkeyw    'decF14',decf14
  194.     mkeyw    'decHelp',dechelp
  195.     mkeyw    'decDo',decdo
  196.     mkeyw    'decF17',decf17
  197.     mkeyw    'decF18',decf18
  198.     mkeyw    'decF19',decf19
  199.     mkeyw    'decF20',decf20
  200.     mkeyw    'decFind',decfind
  201.     mkeyw    'decInsert',decinsert
  202.     mkeyw    'decRemove',decremove
  203.     mkeyw    'decSelect',decselect
  204.     mkeyw    'decPrev',decprev
  205.     mkeyw    'decNext',decnext
  206.     mkeyw    'termtype',vtans52
  207.     mkeyw    'reset',vtinit
  208.     mkeyw    'holdscrn',khold
  209.     mkeyw    'dnscn',dnwpg
  210.     mkeyw    'upscn',upwpg
  211.     mkeyw    'endscn',endwnd
  212.     mkeyw    'homscn',homwnd
  213.     mkeyw    'upone',upone
  214.     mkeyw    'dnone',dnone
  215.     mkeyw    'prtscn',trnprs
  216.     mkeyw    'dump',dmpscn
  217.     mkeyw    'modeline',trnmod
  218.     mkeyw    'break',sendbr
  219.     mkeyw    'lbreak',sendbl
  220.     mkeyw    'hangup',chang
  221.     mkeyw    'nethold',ubhold
  222.     mkeyw    'null',snull
  223.     mkeyw    'logon',klogon
  224.     mkeyw    'logoff',klogof
  225.     mkeyw    'terminalR',vtrmac
  226.     mkeyw    'terminalS',vtsmac
  227.     mkeyw    'DOS',cdos
  228.     mkeyw    'help',cquery
  229.     mkeyw    'status',cstatus
  230.     mkeyw    'exit',cquit
  231.  
  232.                     ; Initialization data.
  233. kbdinlst equ    this byte     ; Kermit IBM initialization time keyboard setup
  234.     mkeyw    '\kgold',scan+59    ; F1    mkeyw 'definition',keycode
  235.     mkeyw    '\kpf2',scan+60        ; F2
  236.     mkeyw    '\kpf3',scan+61        ; F3
  237.     mkeyw    '\kpf4',scan+62        ; F4
  238.     mkeyw    '\kkp0',scan+shift+90    ; VT100 keypad numeric area, SF7
  239.     mkeyw    '\kkp1',scan+shift+86    ; SF3
  240.     mkeyw    '\kkp2',scan+shift+87    ; SF4
  241.     mkeyw    '\kkp3',scan+shift+88    ; SF5
  242.     mkeyw    '\kkp4',scan+67        ; F9
  243.     mkeyw    '\kkp5',scan+68        ; F10
  244.     mkeyw    '\kkp6',scan+shift+84    ; SF1
  245.     mkeyw    '\kkp7',scan+63        ; F5
  246.     mkeyw    '\kkp8',scan+64        ; F6
  247.     mkeyw    '\kkp9',scan+65        ; F7
  248.     mkeyw    '\kkpenter',scan+shift+89 ; SF6
  249.     mkeyw    '\kkpcoma',scan+shift+85  ; SF2
  250.     mkeyw    '\kkpminus',scan+66    ; F8
  251.     mkeyw    '\kkpdot',scan+shift+91    ; SF8
  252.     mkeyw    '\kuparr',scan+72    ; VT100 cursor keys (arrows)
  253.     mkeyw    '\kdnarr',scan+80
  254.     mkeyw    '\klfarr',scan+75
  255.     mkeyw    '\krtarr',scan+77
  256.     mkeyw    '\kupscn',scan+73    ; PgUp  Kermit screen roll back keys
  257.     mkeyw    '\kdnscn',scan+81    ; PgDn
  258.     mkeyw    '\khomscn',scan+71    ; Home
  259.     mkeyw    '\kendscn',scan+79    ; End
  260.     mkeyw    '\kupone',scan+control+132 ; Ctrl PgUp    one line scrolls
  261.     mkeyw    '\kdnone',scan+control+118 ; Ctrl PgDn
  262.     mkeyw    '\kuparr',scan+enhanced+72 ; Enhanced kbd duplicate keys
  263.     mkeyw    '\kdnarr',scan+enhanced+80
  264.     mkeyw    '\klfarr',scan+enhanced+75
  265.     mkeyw    '\krtarr',scan+enhanced+77
  266.     mkeyw    '\kupscn',scan+enhanced+73 ; PgUp Kermit screen roll back keys
  267.     mkeyw    '\kdnscn',scan+enhanced+81 ; PgDn
  268.     mkeyw    '\khomscn',scan+enhanced+71 ; Home
  269.     mkeyw    '\kendscn',scan+enhanced+79    ; End
  270.     mkeyw    '\kupone',scan+control+enhanced+132 ;Ctrl PgUp one line scroll
  271.     mkeyw    '\kdnone',scan+control+enhanced+118 ; Ctrl PgDn
  272.     mkeyw    '\kmodeline',scan+74    ; Kermit toggle mode line  Keypad -
  273.     mkeyw    '\ktermtype',scan+alt+130 ; Kermit toggle terminal type  Alt -
  274.     mkeyw    '\kreset',scan+alt+131    ; Kermit reset terminal  Alt =
  275.     mkeyw    '\kprtscn',scan+control+114 ; Kermit toggle prn scrn  Ctrl *
  276.     mkeyw    '\kdump',scan+control+117 ; Kermit Dump Screen  Ctrl End
  277.     mkeyw    '*',scan+55        ; keypad asterisk
  278.     mkeyw    '*',scan+enhanced+55    ; Enhanced kbd keypad asterisk
  279.     mkeyw    '+',scan+78        ; keypad plus
  280.     mkeyw    '.',scan+shift+83    ; IBM numeric keypad
  281.     mkeyw    '0',scan+shift+82
  282.     mkeyw    '1',scan+shift+79
  283.     mkeyw    '2',scan+shift+80
  284.     mkeyw    '3',scan+shift+81
  285.     mkeyw    '4',scan+shift+75
  286.     mkeyw    '5',scan+shift+76
  287.     mkeyw    '6',scan+shift+77
  288.     mkeyw    '7',scan+shift+71
  289.     mkeyw    '8',scan+shift+72
  290.     mkeyw    '9',scan+shift+73
  291.     mkeyw    tab,scan+15        ; regular Tab key, made special
  292.     mkeyw    cr,scan+28        ; typewriter Enter key
  293.     mkeyw    cr,scan+enhanced+cr    ; Enhanced kbd grey Enter key
  294.     mkeyw    lf,scan+enhanced+control+lf ; Enhanced grey Control Enter
  295.     mkeyw    '/',scan+enhanced+'/'    ; Enhanced kbd grey foward slash
  296.     mkeyw    '\0',scan+control+3    ; Control at-sign sends null
  297.     mkeyw    '\0',scan+control+shift+3 ; Control Shift at-sign sends null
  298.     mkeyw    '\x7f',scan+83        ; Del key sends DEL
  299.     mkeyw    '\x7f',scan+enhanced+83 ; Enhanced duplicate DEL sends DEL
  300.     mkeyw    '\x7f',scan+14        ; Backspace key sends DEL
  301.     mkeyw    '\kexit',scan+alt+45    ; Exit connect mode  Alt X
  302.     mkeyw    '\kstatus',scan+alt+31    ; Connect mode status  Alt S
  303.     mkeyw    '\kbreak',scan+alt+48    ; Send a Break  Alt B
  304.     mkeyw    '\kbreak',scan+control+0; Control-Break sends a Break too
  305.     mkeyw    '\khelp',scan+alt+35    ; Connect mode drop down menu  Alt H
  306.     dw    0        ; end of table marker
  307.  
  308.                     ;** LK250 support begin
  309. kb250lst equ    this byte             ; Extensions for DEC LK250 keyboard
  310.     mkeyw    escape,scan+104        ; Compose maps to ESC
  311.         mkeyw   '\x7f',scan+14          ; Backspace key sends DEL
  312.         mkeyw   bs,scan+shift+14        ; Shift-Backspace key sends BS
  313.     mkeyw    cr,scan+28        ; Return key sends CR
  314.     mkeyw    lf,scan+shift+28    ; Shift-Return sends LF
  315.     mkeyw    tab,scan+15        ; Tab sends TAB
  316.                     ; the top-row function keys
  317.     mkeyw    '\kholdscrn',scan+59    ; DEC Hold
  318.     mkeyw    '\kprtscn',scan+60    ; DEC Print Screen
  319. ;;;;    mkeyw    '{\{kstatus}\{kexit}}',scan+61    ; DEC Set-Up
  320.     mkeyw    '\kbreak',scan+63    ; DEC Break
  321.     mkeyw    '\kdecF6',scan+64    ; DEC F6
  322.     mkeyw    '\kdecF7',scan+65    ; DEC F7
  323.     mkeyw    '\kdecF8',scan+66    ; DEC F8
  324.     mkeyw    '\kdecF9',scan+67    ; DEC F9
  325.     mkeyw    '\kdecF10',scan+68    ; DEC F10
  326.     mkeyw    '\kdecF11',scan+95    ; DEC F11
  327.     mkeyw    '\kdecF12',scan+96    ; DEC F12
  328.     mkeyw    '\kdecF13',scan+97    ; DEC F13
  329.     mkeyw    '\kdecF14',scan+98    ; DEC F14
  330.     mkeyw    '\kdecHelp',scan+99    ; DEC Help
  331.     mkeyw    '\kdecDo',scan+100    ; DEC DO
  332.     mkeyw    '\kdecF17',scan+101    ; DEC F17
  333.     mkeyw    '\kdecF18',scan+102    ; DEC F18
  334.     mkeyw    '\kdecF19',scan+103    ; DEC F19
  335.     mkeyw    '\kdecF20',scan+84    ; DEC F20
  336.                     ; the cursor/select cluster
  337.     mkeyw    '\kdecFind',scan+85    ; DEC Find
  338.     mkeyw    '\kdecInsert',scan+86    ; DEC Insert Here
  339.     mkeyw    '\kdecRemove',scan+87    ; DEC Remove
  340.     mkeyw    '\kdecSelect',scan+88    ; DEC Select
  341.     mkeyw    '\kdecPrev',scan+89    ; DEC Prev
  342.     mkeyw    '\kdecNext',scan+90    ; DEC Next
  343.     mkeyw    '\kuparr',scan+91    ; up arrow
  344.     mkeyw    '\klfarr',scan+92    ; left arrow
  345.     mkeyw    '\krtarr',scan+93    ; right arrow
  346.     mkeyw    '\kdnarr',scan+94    ; down arrow
  347.                     ; the DEC editing keypad
  348.     mkeyw    '\kgold',scan+106    ; F1
  349.     mkeyw    '\kpf2',scan+107    ; F2
  350.     mkeyw    '\kpf3',scan+108    ; F3
  351.     mkeyw    '\kpf4',scan+109    ; F4
  352.     mkeyw    '\kkp7',scan+shift+71    ; KP7
  353.     mkeyw    '\kkp8',scan+shift+72    ; KP8
  354.     mkeyw    '\kkp9',scan+shift+73    ; KP9
  355.     mkeyw    '\kkpminus',scan+74    ; KP-
  356.     mkeyw    '\kkp4',scan+shift+75    ; KP4
  357.     mkeyw    '\kkp5',scan+shift+76    ; KP5
  358.     mkeyw    '\kkp6',scan+shift+77    ; KP6
  359.     mkeyw    '\kkpcoma',scan+78    ; KP,
  360.     mkeyw    '\kkp1',scan+shift+79    ; KP1
  361.     mkeyw    '\kkp2',scan+shift+80    ; KP2
  362.     mkeyw    '\kkp3',scan+shift+81    ; KP3
  363.     mkeyw    '\kkpenter',scan+105    ; keypad enter
  364.     mkeyw    '\kkpenter',scan+shift+105 ; keypad enter
  365.     mkeyw    '\kkp0',scan+shift+82    ; KP0
  366.     mkeyw    '\kkpdot',scan+shift+83    ; KP.
  367.                     ; some useful Kermit keys
  368.         mkeyw   '\kupscn',scan+alt+89   ; PgUp  Kermit screen roll back keys
  369.         mkeyw   '\kdnscn',scan+alt+90   ; PgDn
  370.         mkeyw   '\khomscn',scan+alt+85  ; Home
  371.         mkeyw   '\kendscn',scan+alt+88  ; End
  372.         mkeyw   '\kupone',scan+control+89 ; Ctrl PgUp  one line scrolls
  373.         mkeyw   '\kdnone',scan+control+90 ; Ctrl PgDn
  374.         mkeyw   '\kexit',scan+alt+45    ; Exit connect mode  Alt X
  375.         mkeyw   '\kstatus',scan+alt+31  ; Connect mode status  Alt S
  376.         mkeyw   '\kbreak',scan+alt+48   ; Send a Break  Alt B
  377.         mkeyw   '\kbreak',scan+control+108 ; Control-Break sends a Break too
  378.         mkeyw   '\khelp',scan+alt+35    ; Connect mode drop down menu  Alt H
  379.         mkeyw   '\ktermtype',scan+alt+130 ; Kermit toggle terminal type  Alt -
  380.         mkeyw   '\kreset',scan+alt+131  ; Kermit reset terminal  Alt =
  381.         mkeyw   '\kprtscn',scan+control+109 ; Kermit toggle prn scrn  Ctrl *
  382.         mkeyw   '\kdump',scan+control+88 ; Kermit Dump Screen  Ctrl End
  383.     dw    0            ; end of table marker
  384. got250    db    0            ;** LK250 present if non-zero
  385.                     ;** LK250 support end
  386. kbcodes    dw    80h            ; keyboard read codes, 80h=not inited
  387. data    ends
  388.  
  389. ;            Documentation
  390. ;Translating a key:
  391. ;   The translator is called to obtain keyboard input; it sends characters to
  392. ; the serial port through standard controlled echo procedures or invokes
  393. ; named procedures. It returns carry clear when its operation is completed
  394. ; for normal actions and carry set when Connect mode must be exited. When
  395. ; Connect mode is exited the just read char should be passed in Kbdflg 
  396. ; to msster.asm for invoking actions such as Status, send a break,
  397. ; quit connect mode; system dependent procedure Term is responsible for this. 
  398. ;
  399. ;  Principal procedures are -
  400. ;    msuinit        Initializes keyboard translator in this file when
  401. ;            Kermit first begins. Installs dfkey and shkey as the
  402. ;            procedures used for Set Key and Show Key. Sys Indep.
  403. ;            Called from msx or msy init procs. System Independent.
  404. ;    keybd        Performs the translation, outputs chars to the serial
  405. ;            port or invokes a Kermit action routine. Sys Indep.
  406. ;    dfkey        Defines a key's translation. Reads command line
  407. ;            via Kermit's command parser comnd. System Independent.
  408. ;    shkey        Shows translation of a key. Requests user to push
  409. ;            selected key. System Independent.
  410. ;
  411. ;    kbdinit        optional. Initializes the translation tables when
  412. ;            Kermit starts up. Called by msuinit. System Dependent.
  413. ;    getkey        Performs the keyboard read and returns results in
  414. ;            a standardized system independent format. Sys Depend.
  415. ;    postkey        called by active translator after obtaining a keycode.
  416. ;            Used to provide extra local actions (keyclick) only
  417. ;            in Connect mode (not during Set/Show key commands).
  418. ;            Called by keybd. System dependent.
  419. ; Supporting system independent procedures are -
  420. ; shkfre (show string free space), tstkeyw (finds user's keyword in the verb
  421. ; table), insertst (insert string in buffer), remstr (delete string in buffer).
  422. ;
  423. ;   System dependent procedure Getkey reads a keycode (usually via a Bios
  424. ; call). On IBM compatible machines this yields <ah=scan code, al=ascii>
  425. ; for ordinary keys, or <ah=scan code, al=0> for special keys such as F1,
  426. ; or <ah=0, al=###> when Alt### is used.
  427. ; For any system, the canonical output form is the key's code in Keycode.
  428. ; Place the ascii code (or scan code if none) in byte Keycode and ancillary
  429. ; info (shift states plus marker bit for scan codes) in byte Keycode + 1.
  430. ;   Table Aliaskey is a list of scan code/ascii codes for keys which appear
  431. ; more than once on a keyboard. This list is examined to distinguish such
  432. ; aliased keys (those on an auxillary keypad) from an ordinary ascii key,
  433. ; and the aliased key is then referenced by its scan code rather than by
  434. ; the ordinary ascii code. Aliaskey is machine and keyboard dependent.
  435. ;
  436. ;    Procedure Keybd calls Getkey for the Keycode, checks list of translatable
  437. ; keys Keylist, and then either sends an ascii string (one or more characters)
  438. ; or invokes a Kermit action verb. List Dirlist indicates what kind of 
  439. ; translation to do. Keybd is system independent but may contain system
  440. ; dependent special actions such as echoing keyclicks. Keybd calls system
  441. ; dependent procedure Postkey just after calling getkey so local actions
  442. ; such as keyclicks can be activated only during Connect mode operations.
  443. ;
  444. ;    Keylist is a packed but unordered list of 16 bit keycodes which need
  445. ; translation. The lower order byte holds a key code (ascii char or scan code)
  446. ; while the high byte holds a scan code marker bit (0 if ascii code in low
  447. ; byte) plus any ancillary keyboard information such as Control/Shift/Alt/Meta
  448. ; keys being held down; these are of use in Show Key presentations.
  449. ;    Dirlist parallels Keylist to provide the kind of translation, verb or
  450. ; string, in the two highest bits with the other bits holding either
  451. ; a single new replacement character or the item number in lists of verbs
  452. ; or strings. If neither verb nor strng type bits are set in a dirlist
  453. ; word then the translation is a single new character held in the lower
  454. ; eight bits of that dirlist word.
  455. ;
  456. ;    The number of key translations is assembly constant Maxkeys (def 128).
  457. ;    The maximum number of strings is assembly constant Maxstngs (def 64).
  458. ;    The maximum number of verbs is 256 and is set by building table Kverbs.
  459. ;
  460. ;   For verbs, use the Item number from the Director table Dirlist to select
  461. ; a procedure offset from the structured list Kverbs and jump to that offset.
  462. ; Most verb procedures return carry clear to stay within Connect mode.
  463. ; Verbs requiring exiting Connect mode return carry set and may set byte
  464. ; Kbdflg to a char code which will be read by msster.asm for activating a
  465. ; transient Kermit action such as send a break (Kbdflg = 'b').
  466. ; Kbdflg is stored in msster.asm (as zero initially, meaning ignore it).
  467. ; Action verb procedures are normally located in a system dependent file.
  468. ;
  469. ;   For multi-char strings, use Item number from Director table Dirlist to
  470. ; select a pointer to a string. The list of string pointers is Sptable
  471. ; (string pointer table) which holds the offset in the data segment of the
  472. ; strings stored in buffer Stbuf. In stbuf strings are held as: one byte of
  473. ; length of following text and then the text itself (permits embedded nulls).
  474. ;  Use Chrout to send each string character, and finally return from Keybd
  475. ; with carry clear.
  476. ;
  477. ;   For single character replacements obtain the new character from the lower
  478. ; order byte of Director table Dirlist. If the character is Kermit's present
  479. ; escape character return from Keybd carry set to leave connect mode.
  480. ; Otherwise, send the character via Chrout and return from Keybd carry clear.
  481.  
  482. ; Keylist table format:
  483. ;    7 bits   1 bit   8 bits
  484. ; +----------+----+------------+ scan bit = 1 if key's code is non-ascii
  485. ; | aux info |scan| key's code | aux info = system dependent, used only to
  486. ; +----------+----+------------+            help identify key
  487. ;
  488. ; Dirlist table format          v s    meaning
  489. ;   1   1      14 bits         0 0    copy out one byte translation
  490. ; +---+---+--------------------+  1 0    copy out multi-char string number Item
  491. ; | v | s | item # or new char |  0 1    do action verb number Item
  492. ; +---+---+--------------------+  1 1    (not used)
  493. ;
  494. ; Table kverbs is organized by macro mkeyw as -
  495. ;    kverbs    db    number of table entries
  496. ;    (each entry is in the form below:)
  497. ;        db    number of bytes in verbname
  498. ;        db    'verbname'        variable length
  499. ;        db    '$'            for printing
  500. ;        dw    value            offset of procedure
  501. ;
  502. ;
  503. ;   Dfkey defines a key to be itself (undefines it) or a single replacement
  504. ; character or a character string or a Kermit action verb. Dfkey requires
  505. ; a command line so that it may be invoked by Take files but can be forced
  506. ; to prompt an interactive user to push a key. Syntax is discussed below.
  507. ; Note that redefined keys have their old definitions cleared so that
  508. ; old string space is reclaimed automatically.
  509. ;
  510. ;   Shkey displays a key's definition and the user is asked to push the
  511. ; selected key. The free space for strings is always shown afterward. See
  512. ; below for syntax.
  513. ;
  514. ;   Kbdinit is an optional routine called when Kermit starts up. It fills in
  515. ; the translation tables with desirable default values to save having to
  516. ; use long mskermit.ini files. The default values are stored in a structured
  517. ; table similar to (but not the same as) Dfkey's command lines; the keycode
  518. ; values are preset by hand to 16 bit numbers.
  519.  
  520. ;Defining a key:
  521. ; Command is SET KEY <key ident><whitespace><definition>
  522. ;
  523. ; <key ident> is
  524. ;        a single ordinary ascii char or
  525. ;        the numerical equivalent of an ascii char or
  526. ;        a Scan Code written as a number or
  527. ;        keyword SCAN followed by a number.
  528. ;        ?    Displays help message.
  529. ;    Numbers and Binary codes are of the form
  530. ;        \123    a decimal number
  531. ;        \o456    an octal number        base letters o, d, x can be
  532. ;        \d213    a decimal number    upper or lower case
  533. ;        \x0d    a hex number
  534. ;        \{b###}  braces around above material following slash.
  535. ;
  536. ; <whitespace> is one or more spaces and or tabs.
  537. ;
  538. ; <definition> is
  539. ;    missing altogether which "undefines" a key.
  540. ;    \Kverb        for a Kermit action verb; upper or lower case K is ok
  541. ;    \{Kverb}    ditto. Verb is the name of an action verb.
  542. ;    text        a string with allowed embedded whitespace and embedded
  543. ;            binary chars as above. This kind of string may not
  544. ;            commence with sequences \K or \{K; use braces below.
  545. ;    {text}        string confined to material within but excluding
  546. ;            the braces. Note, where the number of opening braces
  547. ;            exceeds the number of closing braces the end of line
  548. ;            terminates the string: {ab{}{{c}d ==> ab{}{{c}d
  549. ;            but  {ab}{{c}d ==> ab.
  550. ;    ?        Displays help message and lists all action verbs.
  551. ;
  552. ;    If Set Key is given interactively, as opposed to within a Take
  553. ;    file, the system will prompt for inputs if none is on the command
  554. ;    line. The response to Push key to be defined cannot be edited.
  555. ;
  556. ;    Text which reduces to a single replacement character is put into a
  557. ;    table separate from the multi-character strings (maxstng of these).
  558. ;    A key may be translated into any single 8 bit code.
  559. ;    
  560. ;    Comments can follow a Kermit action verb or a braced string; no
  561. ;    semicolon is required since all are stripped out by the Take file
  562. ;    reader before the defining text is seen by SET KEY.
  563. ;
  564. ;    The current Kermit escape character cannot be translated without
  565. ;    subtrafuge.
  566. ;
  567. ;    Examples:
  568. ;        Set Key q z
  569. ;                makes key q send character z
  570. ;        Set Key \7 \27[0m
  571. ;                makes key Control G send the four byte
  572. ;                string  ESC [ 0 m
  573. ;        Set Key q
  574. ;                undefines key q so it sends itself (q) again.
  575. ;        Set Key \2349 \kexit
  576. ;                defines IBM Alt-X to invoke the leave connect
  577. ;                mode verb "exit" (Kermit's escape-char ^] C).
  578. ;        Set Key \x0c Login \{x0d}myname\{x0d}mypass\x0d
  579. ;                defines Control L to send the string
  580. ;                Login <cr>myname<cr>mypass<cr>
  581. ;
  582. ; Alternative Set Key syntax for backward compatibility with previous versions
  583. ;    The same forms as above except the key identification number must
  584. ;    be decimal and must Not have a leading backslash. Example:
  585. ;    Set Key Scan 59 This is the F1 key
  586. ;
  587. ;    If the definition is omitted it may be placed on the following line;
  588. ;    if that line is also empty the key is undefined (defined as Self).
  589. ;    A warning message about obsolete syntax will be given followed by
  590. ;    the key's modern numerical value and new definition. Only "special"
  591. ;    keys (those not producing ascii codes) are compatible with this
  592. ;    translator.
  593. ;
  594. ;Showing a key:
  595. ; Command is SHOW KEY <cr>
  596. ; System prompts user to press a key and shows the definition plus the
  597. ; free space for strings. Query response results in showing all definitions.
  598. ;            End Documentation
  599.  
  600. code    segment    public 'code'
  601.         ; system independent external items
  602.     extrn    comnd:near, prompt:near, iseof:near    ; in msscmd
  603.     extrn    strlen:near                ; in mssfil
  604.     extrn    cnvlin:near, katoi:near, decout:near    ; in msster
  605.         ; system dependent external items
  606.     extrn    beep:near, khold:near, ubhold:near    ; in msxibm &msyibm
  607.     extrn    vclick:near                ; in mszibm
  608.         ; these are system dependent action verbs, in msxibm & msyibm 
  609.     extrn    uparrw:near, dnarrw:near, rtarr:near, lfarr:near
  610.     extrn    pf1:near, pf2:near, pf3:near, pf4:near,    kp0:near, kp1:near
  611.     extrn    kp2:near, kp3:near, kp4:near, kp5:near, kp6:near, kp7:near
  612.     extrn    kp8:near, kp9:near, kpminus:near, kpcoma:near, kpenter:near
  613.     extrn    kpdot:near, decf6:near, decf7:near, decf8:near, decf9:near
  614.     extrn    decf10:near, decf11:near, decf12:near, decf13:near
  615.     extrn    decf14:near, dechelp:near, decdo:near, decf17:near
  616.     extrn    decf18:near, decf19:near, decf20:near, udkclear:near
  617.     extrn    decfind:near, decinsert:near, decremove:near
  618.     extrn    decselect:near, decprev:near, decnext:near
  619.     extrn    chrout:near, cstatus:near, cquit:near, cquery:near
  620.     extrn    vtans52:near, vtinit:near, dnwpg:near, upwpg:near
  621.     extrn    endwnd:near, homwnd:near, upone:near, dnone:near, trnprs:near
  622.     extrn    trnmod:near, sendbr:near, sendbl:near, dmpscn:near, snull:near
  623.     extrn    chang:near, klogon:near, klogof:near, cdos:near
  624.     extrn    vtrmac:near, vtsmac:near, cplatin:near, nrc2cp:near
  625.     extrn    cpdecsg:near
  626.     assume    cs:code, ds:data, es:data
  627.  
  628. ; Begin system independent Keyboard Translator code
  629.  
  630. ; MSUINIT performs Kermit startup initialization for this file.
  631. ; Note, shkadr and stkadr are pointers tested by Set/Show Key calls. If they
  632. ; are not initialized here then the older Set/Show Key procedures are called.
  633. MSUINIT    PROC    NEAR            ; call from msx/msy init code
  634.     call    kbdinit            ; optional: init translator tables
  635.     mov    shkadr,offset shkey    ; declare keyboard translator present
  636.     mov    stkadr,offset dfkey    ; via Show and Set Key proc addresses
  637.     ret
  638. MSUINIT    ENDP
  639.  
  640. ; Call Keybd to read a keyboard char (just returns carry clear if none) and
  641. ; 1) send the replacement string (or original char if not translated)
  642. ;    out the serial port, or
  643. ; 2) execute a Kermit action verb.
  644. ; Returns carry set if Connect mode is to be exited, else carry clear.
  645. ; Modifies registers ax and bx. 
  646. KEYBD    PROC    NEAR            ; active translator
  647.     mov    ttyact,1        ; doing single char output
  648.     cmp    stringcnt,0        ; any leftover string chars?
  649.     je    keybd0            ; e = no
  650.     jmp    keyst2            ; yes, finish string
  651. keybd0:    call    getkey            ; read keyboard
  652.     jnc    keybd1            ; nc = data available
  653.     jmp    keybdx            ; else just return carry clear
  654. keybd1:    call    postkey            ; call system dependent post processor
  655.     cmp    nkeys,0            ; is number of keys defined = 0?
  656.     jz    keybd3            ; z = none defined
  657.     push    di            ; search keylist for this keycode
  658.     push    cx            ; save some registers    
  659.     push    es
  660.     mov    di,offset keylist    ; list of defined keycode words
  661.     mov    ax,keycode        ; present keycode
  662.     mov    cx,nkeys        ; number of words to examine
  663.     push    ds
  664.     pop    es            ; make es:di point to data segment
  665.     cld
  666.     repne    scasw            ; find keycode in list
  667.     pop    es            ; restore regs
  668.     pop    cx
  669.     je    keybd1b            ; e = found, work with present di
  670.     pop    di            ; restore original di
  671.     test    keycode,scan        ; is this a scan code?
  672.     jz    keybd3            ; z = no, it's ascii, use al as char
  673.     call    beep            ; say key is a dead one
  674.     clc
  675.     ret                ; and exit with no action
  676.  
  677. keybd1b:sub    di,2            ; correct for auto increment
  678.     sub    di,offset keylist    ; subtract start of list ==> listptr
  679.     mov    ax,dirlist[di]        ; ax = contents of director word
  680.     pop    di            ; restore original di
  681.                     ; dispatch on Director code
  682.     test    ax,verb            ; verb only?
  683.     jnz    keyvb            ; e = yes
  684.     test    ax,strng        ; multi-char string only?
  685.     jnz    keyst            ; e = yes, else single char & no xlat.
  686.                     ;
  687.                     ; do single CHAR output (char in al)
  688. keybd3:    cmp    al,trans.escchr        ; Kermit's escape char?
  689.     je    keybd3a            ; e = yes, handle separately
  690.     call    xltkey            ; do character set translation
  691.     call    chrout            ; transmit the char
  692.     clc                ; return success
  693.     ret
  694. keybd3a:stc                ; set carry for jump to Quit
  695.     ret
  696.  
  697. keyvb:    and    ax,not(verb+strng)    ; VERB (ax=index, remove type bits)
  698.     mov    bx,offset kverbs    ; start of verb table
  699.     cmp    al,byte ptr [bx]    ; index > number of entries?
  700.     jae    keybdx            ; ae = illegal, indices start at 0
  701.     inc    bx            ; bx points to first entry
  702.     push    cx            ; save reg
  703.     mov    cx,ax            ; save the index in cx
  704.     inc     cx            ; counter, indices start at 0
  705. keyvb1:    mov    al,byte ptr [bx]    ; cnt value
  706.     xor    ah,ah
  707.     add    ax,4            ; skip text and '?' and value word
  708.     add    bx,ax            ; look at next slot
  709.     loop    keyvb1            ; walk to correct slot
  710.     sub    bx,2            ; backup to value field
  711.     pop    cx            ; restore reg
  712.     mov    bx,[bx]            ; get value field of this slot
  713.     cmp    bx,0            ; jump address defined?
  714.     je    keybdx            ; e = no, skip the action
  715.     jmp    bx            ; perform the function
  716.  
  717. keyst:    and    ax,not(verb+strng)    ; STRING (ax=index, remove type bits)
  718.     shl    ax,1            ; convert to word index
  719.     push    si            ; save working reg
  720.     mov    si,ax            ; word subscript in table
  721.     mov    si,sptable[si]        ; memory offset of selected string
  722.     xor    cx,cx            ; init string length to null
  723.     cmp    si,0            ; is there a string pointer present?
  724.     je    keyst1            ; e = no, skip operation
  725.     cld                ; scan forward
  726.     mov    cl,byte ptr [si]    ; get string length byte
  727.     inc    si
  728. keyst1:    mov    stringcnt,cx
  729.     mov    stringptr,si
  730.     pop    si
  731.     jcxz    keybdx            ; z = null length
  732.  
  733. keyst2:    push    si
  734.     mov    si,stringptr        ; pointer to next string char
  735.     cld
  736.     lodsb                ; get new string char into al
  737.     pop    si
  738.     dec    stringcnt        ; string chars remaining
  739.     inc    stringptr
  740.     cmp    stringcnt,0        ; end of the string?
  741.     jne    keyst3            ; ne = no
  742.     mov    ttyact,0        ; pretend not single char output
  743. keyst3:    call    keysv            ; scan for embedded verbs
  744.     jc    keyst4            ; c = not found, al has string char
  745.     jmp    bx            ; perform the verb (bx = address)
  746. keyst4:    call    xltkey            ; do character set translation
  747.     jmp    chrout            ; send out the char in al
  748.  
  749. keybdx:    clc                ; return success (nothing to do)
  750.     ret
  751. KEYBD    ENDP
  752.  
  753. ; Scan for keyboard verbs embedded in outgoing string. If found update
  754. ; string pointer and count to just beyond the verb and return action routine
  755. ; address in bx with carry clear. If failure return carry set and no change.
  756.  
  757. keysv    proc    near
  758.     push    ax
  759.     push    si
  760.     push    di
  761.     cmp    al,'\'            ; escape?
  762.     jne    keysv7            ; ne = no
  763.     mov    cx,stringcnt        ; chars remaining
  764.     mov    si,stringptr        ; address of next char to read
  765.     mov    brace,0            ; assume not using braces
  766.     cmp    byte ptr [si],braceop    ; starts with \{?
  767.     jne    keysv1            ; ne = no
  768.     inc    si            ; skip the opening brace
  769.     dec    cx
  770.     mov    brace,bracecl        ; expect closing brace
  771. keysv1:    cmp    byte ptr [si],'K'    ; starts with \{K or \K?
  772.     je    keysv2            ; e = yes
  773.     cmp    byte ptr [si],'k'    ; starts as \{k or \k?
  774.     jne    keysv7            ; ne = no, then it's a string
  775. keysv2:    inc    si            ; yes, skip the K too
  776.     dec    cx
  777.     mov    di,offset tranbuf    ; copy verb name to this work buffer
  778.     xor    ax,ax
  779.     mov    [di],ax            ; init the buffer to empty
  780. keysv3:    cld
  781.     jcxz    keysv4            ; z = no more string chars
  782.     lodsb                ; scan til closing brace or w/s or end
  783.     dec    cx
  784.     cmp    al,brace        ; closing brace?
  785.     je    keysv4            ; e = yes
  786.     cmp    al,spc            ; white space or control char?
  787.     jbe    keysv3            ; be = yes
  788.     mov    [di],ax            ; copy to tranbuf and terminate
  789.     inc    di
  790.     jmp    short keysv3
  791. keysv4:    push    si            ; save input reading position
  792.     mov    si,offset tranbuf    ; where verb starts (needs si)
  793.     call    tstkeyw            ; find keyword, bx = action routine
  794.     pop    si
  795.     jc    keysv7            ; c = no such verb
  796.     cmp    brace,0            ; need to end on a brace?
  797.     je    keysv6            ; e = no
  798.     dec    si            ; break position
  799.     inc    cx
  800.     cld
  801. keysv5:    jcxz    keysv6            ; z = no more string characters
  802.     lodsb                ; read string char
  803.     dec    cx
  804.     cmp    al,brace        ; the brace?
  805.     jne    keysv5            ; ne = no, repeat until it is found
  806. keysv6:    mov    stringptr,si        ; where we finished+1
  807.     mov    stringcnt,cx        ; new count of remaining chars
  808.     pop    di
  809.     pop    si            ; original si, starting place
  810.     pop    ax            ; original ax
  811.     clc
  812.     ret
  813. keysv7:    pop    di            ; verb not found
  814.     pop    si
  815.     pop    ax
  816.     stc
  817.     ret
  818. keysv    endp
  819. ; SET KEY - define a key   (procedure dfkey)
  820. ; SET KEY <key ident><whitespace><new meaning>
  821. ; Call from Kermit level. Returns as ret if failure or as rskp if success.
  822. ;  
  823. DFKEY    PROC    NEAR            ; define a key as a verb or a string
  824.     mov    keycode,0        ; clear keycode
  825.     mov    oldform,0        ; say no old form Set Key yet
  826.     or    byte ptr kbcodes,80h    ; say kbcodes not-initiated
  827.     mov    dx,offset tranbuf    ; our work space
  828.     mov    word ptr tranbuf,0    ; insert terminator
  829.     mov    bx,offset dfhelp1    ; first help message
  830.     mov    ah,cmword        ; parse a word
  831.     call    comnd            ; get key code or original ascii char
  832.     mov    al,taklev        ; reading from Take file
  833.     mov    msutake,al        ; save here
  834.     or    ah,ah            ; any text given?
  835.     jnz    dfkey12            ; nz = yes, so don't consider prompts
  836.                     ; interactive key request
  837.     cmp    taklev,0        ; in a Take file?
  838.     je    dfkey10            ; e = no, prompt for keystroke
  839.     jmp    dfkey0            ;  else say bad syntax
  840. dfkey10:mov    ah,prstr
  841.     mov    dx,offset dfaskky    ; ask for key to be pressed
  842.     int    dos
  843. dfkey11:call    getkey            ; read key ident from keyboard
  844.     jc    dfkey11            ; c = no response, wait for keystroke
  845.     mov    ah,prstr        ; display cr/lf
  846.     mov    dx,offset crlf
  847.     int    dos
  848.     call    shkey0            ; show current definition (in SHKEY)
  849.     jmp    dfkey1e            ; prompt for and process definition
  850.  
  851. dfkey12:                ; Look for word SCAN and ignore it
  852.     mov    dx,word ptr tranbuf    ; get first two characters
  853.     or    dx,2020h        ; map upper to lower case
  854.     cmp    dx,'cs'            ; first two letters of word "scan"?
  855.     je    dfkey            ; e = yes, skip the word
  856.     cmp    dx,'lc'            ; first two letters of word "clear"?
  857.     je    dfkey15            ; e = yes, reinit keyboard [2.31]
  858.     cmp    dx,'fo'            ; first two letters of "off"
  859.     je    dfkey13            ; e = yes, use DOS keyboard calls
  860.     cmp    dx,'no'            ; first two letters of "on"
  861.     je    dfkey14            ; e = yes, use standard kbd calls
  862.     cmp    ah,1            ; number of characters received
  863.     ja    dfkey1            ; a = more than one, decode
  864.     mov    ah,byte ptr tranbuf    ; get the single char
  865.     mov    byte ptr keycode,ah    ; store as ascii keycode
  866.     jmp    dfkey1b            ; go get definition
  867.  
  868. dfkey13:mov    dosflg,0ffh        ; set DOS keyboard read flag
  869.     jmp    short dfkey14a
  870. dfkey14:mov    dosflg,0        ; clear DOS keyboard read flag
  871. dfkey14a:mov    ah,cmeol        ; get end of line confirmation
  872.     call    comnd
  873.     ret
  874.  
  875. dfkey15:mov    ah,cmeol
  876.     call    comnd            ; confirm request before proceeding
  877.     jnc    dfkeyc            ; nc = success
  878.     ret                ; failure
  879.  
  880. dfkey0:    mov    dx,offset dfhelp1    ; say bad definition command
  881.     mov    ah,prstr
  882.     int    dos
  883.     stc                ; failure
  884.     ret
  885.  
  886. dfkeyc:                    ; CLEAR key defs, restore startup defs
  887.     mov    cx,maxkeys        ; size of keycode tables
  888.     push    es            ; save register
  889.     push    ds
  890.     pop    es            ; make es point to data segment
  891.     mov    ax,0            ; null, value to be stored
  892.     mov    di,offset dirlist    ; director table
  893.     cld
  894.     rep    stosw            ; clear it
  895.     mov    cx,maxkeys
  896.     mov    di,offset keylist    ; keycode table
  897.     rep    stosw            ; clear it
  898.     mov    cx,maxstng
  899.     mov    di,offset sptable    ; string pointer table
  900.     rep    stosw            ; clear it
  901.     pop    es            ; recover register
  902.     mov    strmax,offset stbuf    ; clear string buffer, free space ptr
  903.     mov    stbuf,0            ; first element of buffer 
  904.     mov    nkeys,0            ; clear number of defined keys
  905.     call    msuinit            ; restore startup definitions
  906.     clc                ; success
  907.     ret
  908.                     ; Multi-char key identification
  909. dfkey1:    mov    si,offset tranbuf    ; point to key ident text
  910.     cmp    byte ptr [si],'0'    ; is first character numeric?
  911.     jb    dfkey1a            ; b = no
  912.     cmp    byte ptr [si],'9'    ; in numbers?
  913.     ja    dfkey1a            ; a = no
  914.     mov    keycode,scan        ; setup keycode for scan value
  915.     mov    dx,si            ; get length of string in cx
  916.     call    strlen
  917.     push    ds
  918.     pop    es            ; make es point to data segment
  919.     push    si
  920.     add    si,cx            ; point at string terminator
  921.     mov    di,si
  922.     inc    di            ; place to store string (1 byte later)
  923.     inc    cx            ; include null terminator
  924.     std                ; work backward
  925.     rep    movsb            ; move string one place later
  926.     cld
  927.     pop    si
  928.     mov    byte ptr [si],'\'    ; make ascii digits into \nnn form
  929.     mov    oldform,0ffh        ; set old form flag
  930.     mov    dx,offset kwarnmsg    ; tell user this is old form
  931.     mov    ah,prstr
  932.     int    dos
  933. dfkey1a:call    katoi            ; convert ascii number to binary in ax
  934.     jc    dfkey0            ; c = no number converted
  935.     or    keycode,ax        ; store in keycode
  936.  
  937. dfkey1b:                ; Get Definition proper
  938.     test    oldform,0ffh        ; old form Set Key active?
  939.     jz    dfkey1f            ; z = no
  940.     mov    bx,offset tranbuf    ; get new definition on main cmd line
  941.     mov    word ptr [bx],0        ; insert terminator
  942.     mov    dx,offset dfhelp2    ; help for definition of key
  943.     mov    ah,cmline        ; read rest of line into tranbuf
  944.     call    comnd            ; allow null definitions
  945.     or    ah,ah            ; char count zero?
  946.     jz    dfkey1e            ; z = zero, prompt for definition
  947.     jmp    dfkey1g            ; process definition
  948.  
  949. dfkey1e:mov    ah,prstr
  950.     mov    dx,offset crlf
  951.     int    dos
  952.     mov    dx,offset dfaskdf    ; prompt for definition string
  953.      call    prompt            ; Kermit prompt routine
  954.     mov    comand.cmcr,1        ; permit bare carriage returns
  955.     mov    comand.cmwhite,1    ; allow leading whitespace
  956. dfkey1f:mov    bx,offset tranbuf    ; get new definition
  957.     mov    word ptr [bx],0        ; insert terminator
  958.     mov    dx,offset dfhelp2    ; help for definition of key
  959.     mov    ah,cmline        ; read rest of line into tranbuf
  960.     call    comnd
  961.     jc    dfkey1x            ; exit now on ^C from user
  962.     cmp    comand.cmcr,0        ; prompting for definition?
  963.     je    dfkey1g            ; e = no, trim leading whitespace
  964.     mov    comand.cmcr,0        ; turn off allowance for bare c/r's
  965.     jmp    dfkey2            ; interactive, allow leading whitespace
  966. dfkey1x:ret                ; failure exit
  967.  
  968. dfkey1g:xchg    ah,al            ; put byte count in al
  969.     xor    ah,ah            ; clear high byte
  970.     mov    kbtemp,ax        ; and save count in kbtemp
  971.     mov    ah,cmeol        ; get a confirm
  972.     call    comnd
  973.     jc    dfkey1x            ; none so declare parse error
  974.     mov    cx,kbtemp        ; string length
  975.     
  976. dfkey2:                    ; Examine translation
  977.     mov    al,trans.escchr        ; current escape char (port dependent)
  978.     cmp    al,byte ptr keycode    ; is this Kermit's escape char?
  979.     jne    dfkey2a            ; ne = no
  980.     test    keycode,scan        ; see if scan code
  981.     jnz    dfkey2a            ; nz = scan, so not ascii esc char
  982.     mov    dx,offset dfkoops    ; Oops! msg
  983.     mov    ah,prstr        ; complain and don't redefine
  984.     int    dos
  985.     stc                ; failure
  986.     ret
  987.  
  988. dfkey2a:push    di            ; get a director code for this key
  989.     push    cx    
  990.     mov    di,offset keylist    ; list of keycodes
  991.     mov    cx,nkeys        ; number currently defined
  992.     mov    ax,keycode        ; present keycode
  993.     jcxz    dfkey2b            ; cx = 0 means none defined yet
  994.     cld
  995.     push    ds
  996.     pop    es
  997.     repne    scasw            ; is current keycode in the list?
  998.     jne    dfkey2b            ; ne = not in list
  999.     sub    di,2            ; correct for auto increment
  1000.     sub    di,offset keylist
  1001.     mov    listptr,di        ; list pointer for existing definition
  1002.     pop    cx
  1003.     pop    di
  1004.     jmp    dfkey3            ; go process definition
  1005.  
  1006. dfkey2b:pop    cx            ; key not currently defined so
  1007.     pop    di            ;  make a new director entry for it
  1008.     mov    bx,nkeys        ; number of keys previously defined
  1009.     cmp    bx,maxkeys        ; enough space?
  1010.     jae    dfkey2c            ; ae = no, complain
  1011.     shl    bx,1            ; count words
  1012.     mov    listptr,bx        ; index into word list
  1013.     mov    ax,keycode        ; get key's code
  1014.     mov    keylist[bx],ax        ; store it in list of keycodes
  1015.     mov    dirlist[bx],0        ; clear the new director entry
  1016.     inc    nkeys            ; new number of keys
  1017.     jmp    dfkey3            ; go process definition
  1018.  
  1019. dfkey2c:mov    dx,offset keyfull    ; say key space is full already
  1020.     mov    ah,prstr
  1021.     int    dos
  1022.     stc                ; failure
  1023.     ret
  1024.  
  1025. ; listptr has element number in keylist or dirlist; keycode has key's code.
  1026.  
  1027. ; Parse new definition. First look for Kermit verbs as a line beginning
  1028. ; as \K or \{K. Otherwise, consider the line to be a string.
  1029. ; In any case, update the Director table for the new definition.
  1030.  
  1031. dfkey3:    mov    brace,0            ; assume not using braces
  1032.     mov    si,offset tranbuf    ; start of definition text
  1033.     cmp    byte ptr [si],'\'    ; starts with escape char?
  1034.     jne    dfkey5            ; ne = no, so we have a string
  1035.     inc    si            ; skip the backslash
  1036.     cmp    byte ptr [si],braceop    ; starts with \{?
  1037.     jne    dfkey3a            ; ne = no
  1038.     inc    si            ; skip the opening brace
  1039.     mov    brace,bracecl        ; expect closing brace
  1040. dfkey3a:cmp    byte ptr [si],'K'    ; starts with \{K or \K?
  1041.     je    dfkey3b            ; e = yes
  1042.     cmp    byte ptr [si],'k'    ; starts as \{k or \k?
  1043.     jne    dfkey5            ; ne = no, then it's a string
  1044. dfkey3b:inc    si            ; yes, skip the K too
  1045.                     ; Kermit action VERBS
  1046.     push    si            ; save verb name start address
  1047. dfkey4:    cld
  1048.     lodsb                ; scan til closing brace or w/s or end
  1049.     cmp    al,0            ; premature end?
  1050.     je    dfkey4b            ; e = yes, accept without brace
  1051.     cmp    al,brace        ; closing brace?
  1052.     je    dfkey4b            ; e = yes
  1053.     cmp    al,spc            ; white space or control char?
  1054.     ja    short dfkey4        ; a = no, so not at end yet
  1055. dfkey4b:mov    byte ptr[si-1],0    ; insert null terminator
  1056.     pop    si            ; recover start address
  1057.     call    tstkeyw            ; find keyword, kw # returned in kbtemp
  1058.     jc    dfkey4d            ; c = no keyword found, complain
  1059.     call    remstr            ; clear old string, if string
  1060.     mov    ax,kbtemp        ; save keyword number
  1061.     and    ax,not(verb+strng)    ; clear verb / string field
  1062.     or    ax,verb            ; set verb ident
  1063.     mov    si,listptr
  1064.     mov    dirlist[si],ax        ; store info in Director table
  1065.     jmp    dfkey7            ; show results and return success
  1066.  
  1067. dfkey4d:mov    dx,offset verbbad    ; say no such verb
  1068.     mov    ah,prstr
  1069.     int    dos
  1070.     stc                ; failure
  1071.     ret
  1072.  
  1073. ; Here we are left with the definition string; si points to its start, and
  1074. ; kbtemp holds its length (number of bytes). Null termination. If the string
  1075. ; begins with an opening brace it terminates on a matching closing brace
  1076. ; or the end of line, whichever occurs first. Trailing whitespace removed
  1077. ; before examining braces.
  1078. ; Null length strings mean define key as Self.
  1079.                     ; STRING definitions
  1080. dfkey5:    call    remstr            ; first, clear old string, if any
  1081.     mov    si,offset tranbuf    ; si=source, di=dest, convert in-place
  1082.     mov    di,si
  1083.     call    cnvlin            ; convert numbers, cx gets line length
  1084.     mov    si,offset tranbuf    ; provide address of new string
  1085.     cmp    cx,1            ; just zero or one byte to do?
  1086.     jbe    dfkey6            ; e = yes, do as a char
  1087.     call    insertst        ; insert new string, returns reg cx.
  1088.     jc    dfkey5h            ; c = could not do insert
  1089.     mov    si,listptr        ; cx has type and string number
  1090.     mov    dirlist[si],cx        ; update Director table from insertst
  1091.     jmp    dfkey7            ; show results and return success
  1092.  
  1093. dfkey5h:mov    dx,offset strbad    ; display complaint
  1094.     mov    ah,prstr
  1095.     int    dos
  1096.     stc                ; failure
  1097.     ret
  1098.  
  1099.         ; define SINGLE CHAR replacement or CLEAR a key definition.
  1100.         ; cx has char count 1 (normal) or 0 (to undefine the key).
  1101. dfkey6:    jcxz    dfkey6c            ; z = cx= 0, clear definition
  1102.     mov    al,byte ptr [si]    ; get first byte from definition
  1103.     xor    ah,ah            ; set the type bits to Char
  1104.     mov    si,listptr
  1105.     mov    dirlist[si],ax        ; store type and key's new code
  1106.     jmp    dfkey7            ; return success
  1107.  
  1108. dfkey6c:push    si            ; clear a definition,
  1109.     push    di            ; listptr points to current def
  1110.     mov    si,listptr        ; starting address to clear
  1111.     add    si,offset dirlist
  1112.     mov    di,si            ; destination
  1113.     add    si,2            ; source is next word
  1114.     mov    cx,nkeys        ; current number of keys defined
  1115.     add    cx,cx            ; double for listptr being words
  1116.     sub    cx,listptr        ; cx = number of words to move
  1117.     shr    cx,1            ; convert to actual number of moves
  1118.     jcxz    dfkey6d            ; z = none, just remove last word
  1119.     push    es
  1120.     push    ds
  1121.     pop    es            ; make es:di point to data segment
  1122.     cld
  1123.     push    cx            ; save cx
  1124.     rep    movsw            ; move down higher list items
  1125.     pop    cx
  1126.     mov    si,listptr        ; do keylist too, same way
  1127.     add    si,offset keylist
  1128.     mov    di,si
  1129.     add    si,2
  1130.     rep    movsw
  1131.     pop    es
  1132. dfkey6d:mov    si,nkeys        ; clear old highest list element
  1133.     shl    si,1            ; address words
  1134.     mov    dirlist[si],0        ; null the element
  1135.     mov    keylist[si],0        ; null the element
  1136.     dec    nkeys            ; say one less key defined now
  1137.     pop    di            ; restore saved registers
  1138.     pop    si
  1139.  
  1140. dfkey7:    mov    ah,msutake        ; Finish up. In a Take file?
  1141.     or    ah,taklev        ; or even directly
  1142.     cmp    ah,0
  1143.     je    dfkey7a            ; e = no
  1144.     cmp    flags.takflg,0        ; echo Take commands?
  1145.     je    dfkey7b            ; e = no
  1146. dfkey7a:mov    ah,prstr        ; display cr/lf
  1147.     mov    dx,offset crlf
  1148.     int    dos
  1149.     call    shkey0            ; show new definition (in SHKEY)
  1150.     call    shkfre            ; show free string space
  1151. dfkey7b:clc                ; return success
  1152.     ret
  1153. DFKEY    ENDP
  1154.  
  1155. ; SHOW KEY <cr> command. Call from Kermit level. Vectored here by SHOW
  1156. ; command. Replaces obsolete procedure in msx---.
  1157. ; Prompts for a key and shows that key's (or all if ? entered) keycode,
  1158. ; definition, and the key definition free space remaining.
  1159.  
  1160. SHKEY    PROC    NEAR            ; Show key's definition command
  1161.     mov    ah,cmeol        ; get a confirm
  1162.     call    comnd            ; ignore any additional text
  1163.     push    bx
  1164.     mov    dx,offset shkmsg1    ; ask for original key
  1165.     mov    ah,prstr
  1166.     int    dos
  1167.     or    byte ptr kbcodes,80h    ; say kbcodes not-initiated
  1168. shky0:    call    getkey            ; read keyboard, output to keycode
  1169.     jc    shky0            ; wait for a key (c = nothing there)
  1170.     cmp    byte ptr keycode,'?'    ; query for all keys?
  1171.     jne    shky0a            ; ne = no, not a query
  1172.     test    keycode,scan        ; is this a scan code, vs ascii query?
  1173.     jz    shky0c            ; z = no Scan, so it is a query
  1174.  
  1175. shky0a:    mov    ah,prstr        ; show single key. Setup display
  1176.     mov    dx,offset crlf
  1177.     int    dos
  1178.     call    shkey0            ; show just one key
  1179. shky0b:    call    shkfre            ; show free string space
  1180.     jmp    shkeyx            ; exit
  1181.  
  1182. shky0c:    mov    cx,nkeys        ; Show all keys. nkeys = number defined
  1183.     jcxz    shky0b            ; z = none to show
  1184.     mov    si,offset keylist    ; list of definitions
  1185.     push    si            ; save pointer
  1186. shky1:    pop    si            ; recover pointer
  1187.     cld
  1188.     lodsw                ; get a keycode
  1189.     push    si            ; save pointer
  1190.     push    cx            ; save counter
  1191.     mov    keycode,ax        ; save new keycode
  1192.     mov    ah,prstr
  1193.     mov    dx,offset crlf
  1194.     int    dos
  1195.     call    shkey0            ; show this keycode
  1196.  
  1197.     pop    cx            ; pause between screens, recover cntr
  1198.     push    cx            ; save it again
  1199.     dec    cx            ; number yet to be shown
  1200.     jcxz    shky1b            ; z = have now shown all of them
  1201.     mov    ax,nkeys        ; number of defined keys
  1202.     sub    ax,cx            ; minus number yet to be displayed
  1203.     xor    dx,dx            ; clear extended numerator
  1204.     div    twelve            ; two lines per definition display
  1205.     or    dx,dx            ; remainder zero (12 defs shown)?
  1206.     jnz    shky1b            ; nz = no, not yet so keep going
  1207.     mov    ah,prstr
  1208.     mov    dx,offset shkmsg3    ; "push any key to continue" msg
  1209.     int    dos
  1210. shky1a:    call    getkey            ; get any key
  1211.     jc    shky1a            ; c = nothing at keyboard yet, wait
  1212. shky1b:    pop    cx            ; resume loop
  1213.     loop    shky1
  1214.     pop    si            ; clean stack
  1215.     call    shkfre            ; show free string space
  1216.     jmp    shkeyx            ; exit
  1217.  
  1218.         ; show key worker routine, called from above
  1219.                     ; SHKEY0 called by DFKEY just above
  1220. SHKEY0:    test    keycode,scan        ; scan code?
  1221.     jz    shkey1            ; z = no, regular ascii
  1222.  
  1223.                     ; SCAN codes
  1224.     mov    dx,offset scanmsg    ; say Scan Code:
  1225.     mov    ah,prstr
  1226.     int    dos
  1227.     mov    ah,conout
  1228.     mov    dl,'\'            ; add backslash before number
  1229.     int    dos
  1230.     mov    ax,keycode        ; get key's code again
  1231.     call    decout            ; display 16 bit decimal keycode
  1232.     jmp    shkey2            ; go get definition
  1233.  
  1234. shkey1:    mov    dx,offset ascmsg    ; say ASCII CHAR
  1235.     mov    ah,prstr
  1236.     int    dos
  1237.     mov    dl,byte ptr keycode    ; get ascii code (al part of input)
  1238.     mov    ah,conout
  1239.     cmp    dl,spc            ; control code?
  1240.     jae    shkey1a            ; ae = no
  1241.     push    dx            ; save char
  1242.     mov    dl,5eh            ; show caret first
  1243.     int    dos
  1244.     pop    dx
  1245.     add    dl,'A'-1        ; ascii bias
  1246. shkey1a:cmp    dl,del            ; DEL?
  1247.     jne    shkey1b            ; ne = no
  1248.     mov    dl,'D'            ; spell out DEL
  1249.     int    dos
  1250.     mov    dl,'E'
  1251.     int    dos
  1252.     mov    dl,'L'
  1253. shkey1b:int    dos
  1254.     mov    dl,spc            ; add a couple of spaces
  1255.     int    dos
  1256.     int    dos
  1257.     mov    dl,'\'            ; add backslash before number
  1258.     int    dos
  1259.     mov    ax,keycode        ; show 16 bit keycode in decimal
  1260.     call    decout            ; and go get definiton
  1261.  
  1262.                     ; Display defintion
  1263. shkey2:    mov    dx,offset shkmsg2    ; intermediate part of reply
  1264.     mov    ah,prstr        ; " is defined as "
  1265.     int    dos
  1266.     push    di            ; get a director code for this key
  1267.     push    cx    
  1268.     mov    di,offset keylist    ; list of keycodes
  1269.     mov    cx,nkeys        ; number currently defined
  1270.     jcxz    shkey2a            ; z = none
  1271.     mov    ax,keycode        ; present keycode
  1272.     push    ds
  1273.     pop    es            ; use data segment for es:di
  1274.     cld
  1275.     repne    scasw            ; is current keycode in the list?
  1276.     jne    shkey2a            ; ne = not in list
  1277.     sub    di,2            ; correct for auto increment
  1278.     sub    di,offset keylist
  1279.     mov    listptr,di        ; list pointer for existing definition
  1280.     pop    cx
  1281.     pop    di
  1282.     jmp    shkey3            ; go process definition
  1283.  
  1284. shkey2a:pop    cx
  1285.     pop    di
  1286.     mov    dx,offset noxmsg    ; say Self (no translation)
  1287.     mov    ah,prstr
  1288.     int    dos
  1289.     ret                ; return to main show key loop
  1290.  
  1291. shkey3:                    ; translations, get kind of.
  1292.     mov    si,listptr
  1293.     test    dirlist[si],verb    ; defined as verb?
  1294.     jnz    shkey6            ; nz = yes, go do that one
  1295.     test    dirlist[si],strng    ; defined as string?
  1296.     jz    shkey3a            ; z = no
  1297.     jmp    shkey8            ; yes, do string display
  1298. shkey3a:
  1299.     mov    dx,offset ascmsg    ; CHAR. say 'Ascii char:'
  1300.     mov    ah,prstr
  1301.     int    dos
  1302.     mov    ax,dirlist [si]        ; get type and char
  1303.     mov    dl,al            ; put char here for display
  1304.     push    ax            ; save here too
  1305.     mov    ah,conout
  1306.     cmp    dl,spc            ; control code?
  1307.     jae    shkey4            ; ae = no
  1308.     push    dx
  1309.     mov    dl,5eh            ; show caret
  1310.     int    dos
  1311.     pop    dx
  1312.     add    dl,'A'-1        ; add ascii bias
  1313. shkey4:    cmp    dl,del            ; DEL?
  1314.     jne    shkey4a            ; ne = no
  1315.     mov    dl,'D'            ; spell out DEL
  1316.     int    dos
  1317.     mov    dl,'E'
  1318.     int    dos
  1319.     mov    dl,'L'
  1320. shkey4a:int    dos
  1321.     mov    dl,spc            ; add a couple of spaces
  1322.     mov    ah,conout
  1323.     int    dos
  1324.     int    dos
  1325.     mov    dl,'\'            ; add backslash before number
  1326.     int    dos
  1327.     pop    ax            ; recover char
  1328.     xor    ah,ah            ; clear high byte
  1329.     call    decout            ; show decimal value
  1330.     ret                ; return to main show key loop
  1331.  
  1332. shkey6:    mov    ah,prstr        ; VERB
  1333.     mov    dx,offset verbmsg    ; say 'verb'
  1334.     int    dos
  1335.     mov    si,listptr        ; get verb index from director
  1336.     mov    dx,dirlist[si]
  1337.     and    dx,not(verb+strng)    ; remove type bits, leaves verb number
  1338.     mov    bx,offset kverbs    ; table of verbs & actions
  1339.     mov    al,byte ptr [bx]    ; number of keywords
  1340.     xor    ah,ah
  1341.     dec    ax
  1342.     mov    kwcnt,ax        ; save number of last one here
  1343.     cmp    dx,ax            ; asking for more than we have?
  1344.     ja    shkeyx            ; a = yes, exit bad
  1345.     inc    bx            ; point to first slot
  1346.     mov    cx,0            ; current slot number
  1347. shkey6b:cmp    cx,dx            ; this slot?
  1348.     je    shkey6c            ; e = yes, print the text part
  1349.     ja    shkeyx            ; a = beyond, exit bad
  1350.     mov    al,byte ptr [bx]    ; get cnt (keyword length)
  1351.     xor    ah,ah
  1352.     add    ax,4            ; skip over '$' and two byte value
  1353.     add    bx,ax            ; bx = start of next keyword slot
  1354.     inc    cx            ; current keyword number
  1355.     jmp    short shkey6b        ; try another
  1356. shkey6c:inc    bx            ; look at text field
  1357.     mov    dx,bx            ; offset for printing
  1358.     mov    ah,prstr
  1359.     int    dos
  1360.     mov    ah,conout
  1361.     mov    dl,spc            ; add a couple of spaces
  1362.     int    dos
  1363.     int    dos
  1364.     mov    dl,'\'            ; show verb name as \Kverb
  1365.     int    dos
  1366.     mov    dl,'K'
  1367.     int    dos
  1368.     mov    ah,prstr
  1369.     mov    dx,bx            ; show name part again
  1370.     int    dos
  1371.     ret                ; return to main show key loop
  1372.  
  1373. shkey8:    mov    ah,prstr        ; STRING
  1374.     mov    dx,offset strngmsg    ; say String:
  1375.     int    dos
  1376.     mov    si,listptr        ; get index from director
  1377.     mov    bx,dirlist[si]
  1378.     and    bx,not(verb+strng)    ; remove type bits
  1379.     shl    bx,1            ; index words
  1380.     mov    si,sptable[bx]        ; table of string offsets
  1381.     mov    cl,byte ptr [si]    ; get string length byte
  1382.     xor    ch,ch
  1383.     inc    si            ; point to string text
  1384.     mov    ah,conout
  1385. shkey8a:cld
  1386.     lodsb                ; get a byte
  1387.     cmp    al,spc            ; control code?
  1388.     jae    shkey8b            ; ae = no
  1389.     push    ax
  1390.     mov    dl,5eh            ; show caret first
  1391.     int    dos
  1392.     pop    ax
  1393.     add    al,40h            ; convert to printable for display
  1394. shkey8b:mov    dl,al
  1395.     int    dos            ; display it
  1396.     loop    shkey8a            ; do another
  1397.     ret                ; return to main show key loop
  1398.     
  1399. shkeyx:    pop    bx            ; restore reg
  1400.     clc                ; return success
  1401.     ret
  1402. SHKEY    ENDP
  1403.  
  1404. ;;;    keyboard translator local support procedures, system independent
  1405.  
  1406. ; Tstkeyw checks text word pointed to by si against table of keywords (pointed
  1407. ; to by kverbs, made by mkeyw macro); returns in bx either action value or 0.
  1408. ; Returns in kbtemp the number of the keyword and carry clear, or if failure
  1409. ; returns kbtemp zero and carry set.
  1410. ; Keyword structure is:         db    cnt    (length of string 'word')
  1411. ;                 db    'word'    (keyword string)
  1412. ;                 db    '$'    (printing terminator)
  1413. ;                 dw    value    (value returned in bx)
  1414. ; Make these with macro mkeyw such as   mkeyw 'test',15   with the list of
  1415. ; such keywords headed by a byte giving the number of keywords in the list.
  1416. tstkeyw    proc    near
  1417.     push    ax
  1418.     push    cx
  1419.     push    si
  1420.     mov    verblen,0        ; verblen will hold verb length
  1421.     push    si            ; save user's verb pointer
  1422. tstkw1:    cld
  1423.     lodsb                ; get a verb character
  1424.     cmp    al,spc            ; verbs are all non-spaces and above
  1425.     jbe    tstkw2            ; be = done (space or control char)
  1426.     inc    verblen            ; count verb length
  1427.     jmp    short tstkw1        ; printable char, look for more
  1428. tstkw2:    pop    si            ; pointer to verb
  1429.     mov    bx,offset kverbs    ; table of Kermit verb keywords
  1430.     mov    al,byte ptr [bx]    ; number of keywords
  1431.     xor    ah,ah
  1432.     mov    kwcnt,ax        ; save number of keywords here
  1433.     inc    bx            ; point bx to first slot
  1434.     mov    kbtemp,0        ; remember which keyword
  1435.  
  1436. tstkw3:                    ; match table keyword and text word
  1437.     mov    cx,verblen        ; length of user's verb
  1438.     cmp    byte ptr [bx],cl    ; compare length vs table keyword
  1439.     jne    tstkw4            ; ne = not equal lengths, try another
  1440.     push    si            ; lengths match, how about spelling?
  1441.     push    bx
  1442.     inc    bx            ; point at start of keyword
  1443. tstkw3a:mov    ah,byte ptr [bx]    ; keyword char
  1444.     mov    al,byte ptr [si]    ; text char
  1445.     cmp    ah,'A'
  1446.     jb    tstkw3b            ; b = control chars
  1447.     cmp    ah,'Z'
  1448.     ja    tstkw3b            ; a = not upper case alpha
  1449.     add    ah,'a'-'A'        ; convert upper case to lower case
  1450. tstkw3b:cmp    al,'A'
  1451.     jb    tstkw3c
  1452.     cmp    al,'Z'
  1453.     ja    tstkw3c
  1454.     add    al,'a'-'A'        ; convert upper case to lower case
  1455. tstkw3c:cmp    al,ah            ; test characters
  1456.     jne    tstkw3d            ; ne = no match
  1457.     inc     si            ; move to next char
  1458.     inc    bx
  1459.     loop    tstkw3a            ; loop through entire length
  1460. tstkw3d:pop    bx
  1461.     pop    si
  1462.     jcxz    tstkw5            ; z: cx = 0, exit with match;
  1463.                     ;  else select next keyword
  1464. tstkw4:    inc    kbtemp            ; number of keyword to test next
  1465.     mov    cx,kbtemp
  1466.     cmp    cx,kwcnt        ; all done? Recall kbtemp starts at 0
  1467.     jae    tstkwx            ;ae = exhausted search, unsuccessfully
  1468.     mov    al,byte ptr [bx]    ; cnt (keyword length from macro)
  1469.     xor    ah,ah
  1470.     add    ax,4            ; skip over '$' and two byte value
  1471.     add    bx,ax            ; bx = start of next keyword slot
  1472.     jmp    tstkw3            ; do another comparison
  1473.  
  1474. tstkw5:                    ; get action pointer
  1475.     mov    al,byte ptr [bx]    ; cnt (keyword length from macro)
  1476.     xor    ah,ah
  1477.     add    ax,2            ; skip over '$'
  1478.     add    bx,ax            ; now bx points to dispatch value
  1479.     mov    bx,[bx]            ; bx holds dispatch value
  1480.     clc                ; carry clear for success
  1481.     jmp    short tstkwxx        ; exit
  1482.     ret
  1483. tstkwx:    xor    bx,bx            ; exit when no match
  1484.     mov    kbtemp,bx        ; make verb number be zero too
  1485.     stc                ; carry set for failure
  1486. tstkwxx:pop    si
  1487.     pop    cx
  1488.     pop    ax
  1489.     ret
  1490. tstkeyw    endp
  1491.  
  1492. ; Insert asciiz string pointed to by si into string buffer stbuf.
  1493. ; Reg cx has string length upon entry.
  1494. ; Success: returns offset of first free byte (strmax) in string buffer stbuf,
  1495. ; cx = type and Index of new string, and carry clear.
  1496. ; Failure = carry set.
  1497. insertst proc    near
  1498.     push    bx
  1499.     push    dx
  1500.     push    si
  1501.     push    di
  1502.     push    kbtemp        ; save this variable too
  1503.     mov    dx,cx        ; save length of incoming string in dx
  1504.     mov    bx,offset sptable ; table of string offsets
  1505.     mov    kbtemp,0    ; slot number
  1506.     mov    cx,maxstng    ; number of entries, find an empty slot
  1507. insert1:cmp    word ptr[bx],0    ; slot empty?
  1508.     je    insert2        ; e = yes
  1509.     inc    kbtemp        ; remember slot number
  1510.     add    bx,2        ; look at next slot
  1511.     loop    insert1        ; keep looking
  1512.     jmp    short insert4    ; get here if no empty slots
  1513. insert2:            ; see if stbuf has sufficient space
  1514.     mov    cx,dx        ; length of new string to cx
  1515.     mov    di,strmax    ; offset of first free byte in stbuf
  1516.     add    di,cx        ; di = address where this string would end
  1517.     cmp    di,offset stbuf+stbuflen ; beyond end of buffer?
  1518.     jae    insert4        ; ae = yes, not enough room
  1519.     mov    di,strmax    ; point to first free slot in stbuf
  1520.     mov    [bx],di        ; fill slot with address offset of buffer
  1521.     push    es
  1522.     push    ds
  1523.     pop    es        ; point es:di to data segment
  1524.     cld
  1525.     mov    byte ptr [di],cl ; length of text for new string
  1526.     inc    di        ; move to next storage slot
  1527.     rep    movsb        ; copy string text
  1528.     pop    es
  1529.     mov    strmax,di    ; offset of next free byte
  1530.     mov    cx,kbtemp    ; return new slot number with Director Index
  1531.     and    cx,not(strng+verb) ; clear type bits
  1532.     or    cx,strng    ; say type is multi-char string
  1533.     clc            ; say success
  1534.     jmp    short insertx    ; exit
  1535. insert4:stc            ; say no-can-do
  1536. insertx:pop    kbtemp
  1537.     pop    di
  1538.     pop    si
  1539.     pop    dx
  1540.     pop    bx
  1541.     ret
  1542. insertst endp
  1543.  
  1544. ; Remove (delete) string. Enter with listptr preset for director entry.
  1545. ; Acts only on existing multi-char strings; recovers freed space.
  1546. ; All registers preserved.
  1547. remstr    proc    near        
  1548.     push    si
  1549.     mov    si,listptr        ; list pointer
  1550.     test    dirlist[si],strng    ; multi-char string?
  1551.     pop    si
  1552.     jnz    remst1            ; nz = a multi-char string
  1553.     ret                ; else do nothing
  1554. remst1:    push    ax
  1555.     push    bx
  1556.     push    cx
  1557.     push    dx
  1558.     push    si
  1559.     mov    si,listptr
  1560.     mov    ax,dirlist[si]         ; Director table entry
  1561.     and    ax,not(strng+verb) ; clear type bits, leave string's pointer
  1562.     mov    dirlist[si],0        ; clear Director table entry
  1563.     shl    ax,1            ; index words not bytes
  1564.     mov    si,offset sptable     ; list of string offsets in stbuf
  1565.     add    si,ax            ; plus index = current slot
  1566.     mov    bx,[si]            ; get offset of string to be deleted
  1567.     mov    dx,bx            ; save in dx for later
  1568.     mov    cl,byte ptr [bx]    ; get length byte
  1569.     xor    ch,ch            ; get length of subject string
  1570.     inc    cx            ; length byte too, cx has whole length
  1571.     sub    strmax,cx    ; count space to be freed (adj end-of-buf ptr)
  1572.     mov    word ptr [si],0    ; clear sptable of subject string address
  1573.     push    cx            ; save length of purged string
  1574.     push    di            ; save di
  1575.     push    si
  1576.     push    es            ; save es
  1577.     push    ds
  1578.     pop    es        ; setup es:di to be ds:offset of string
  1579.     mov    di,dx        ; destination = start address of purged string
  1580.     mov    si,dx        ; source = start address of purged string
  1581.     add    si,cx        ;  plus string length of purged string.
  1582.     mov    cx,offset stbuf+stbuflen ; 1 + address of buffer end
  1583.     sub    cx,si            ; 1 + number of bytes to move
  1584.     dec    cx            ; number of bytes to move
  1585.     jcxz    remst2            ; z = none
  1586.     cld                ; direction is forward
  1587.     rep    movsb            ; move down preserved strings
  1588. remst2:    pop    es            ; restore regs
  1589.     pop    di
  1590.     pop    si
  1591.     pop    ax        ; recover length of purged string (was in cx)
  1592.     mov    bx,offset sptable     ; string pointer table
  1593.     mov    cx,maxstng        ; max mumber of entries
  1594. remst4:    cmp    [bx],dx        ; does this entry occur before purged string?
  1595.     jbe    remst5        ; be = before or equal, so leave it alone
  1596.     sub    [bx],ax        ; recompute address (remove old string space)
  1597. remst5:    add    bx,2            ; look at next list entry
  1598.     loop    remst4            ; do all entries in sptable
  1599.     pop    si
  1600.     pop    dx
  1601.     pop    cx
  1602.     pop    bx
  1603.     pop    ax
  1604.     ret
  1605. remstr    endp
  1606.  
  1607. shkfre    proc    near            ; show free key & string defs & space
  1608.     push    ax            ; preserves all registers.
  1609.     push    bx
  1610.     push    cx
  1611.     push    dx
  1612.     push    kbtemp
  1613.     mov    dx,offset fremsg
  1614.     mov    ah,prstr
  1615.     int    dos
  1616.     mov    ax,maxkeys        ; max number of key defs
  1617.     sub    ax,nkeys        ; number currently used
  1618.     call    decout            ; show the value
  1619.     mov    ah,prstr
  1620.     mov    dx,offset kyfrdef    ; give key defs msg
  1621.     int    dos
  1622.     mov    bx,offset sptable    ; table of string pointers
  1623.     mov    cx,maxstng        ; number of pointers
  1624.     mov    kbtemp,0        ; number free
  1625. shkfr1:    cmp    word ptr [bx],0        ; slot empty?
  1626.     jne    shkfr2            ; ne = no
  1627.     inc    kbtemp            ; count free defs
  1628. shkfr2:    add    bx,2            ; look at next slot
  1629.     loop    shkfr1            ; do all of them
  1630.     mov    ax,kbtemp        ; number of free defs
  1631.     call    decout            ; display
  1632.     mov    dx,offset stfrdef    ; say free string defs
  1633.     mov    ah,prstr
  1634.     int    dos
  1635.     mov    ax,offset stbuf+stbuflen ; 1 + last byte in stbuf
  1636.     sub    ax,strmax        ; offset of last free byte in stbuf
  1637.     call    decout
  1638.     mov    dx,offset stfrspc    ; give free space part of msg
  1639.     mov    ah,prstr
  1640.     int    dos
  1641.     pop    kbtemp
  1642.     pop    dx
  1643.     pop    cx
  1644.     pop    bx
  1645.     pop    ax
  1646.     ret
  1647. shkfre    endp
  1648.  
  1649. ; Initialize the keyboard tables at Kermit startup time. Optional procedure.
  1650. ; Requires kbdinlst to be configured with mkeyw macro in the form
  1651. ;    mkeyw    'definition',keytype*256+keycode
  1652. ; keytype is 0 for scan codes and non-zero for ascii.
  1653. ; Returns normally.
  1654. kbdinit    proc     near            ; read keyword kbdinlst and setup
  1655.     or    byte ptr kbcodes,80h    ; say kbcodes not-initiated
  1656.     push    ds            ;  initial keyboard assignments.
  1657.     pop    es            ; set es:di to data segment
  1658.     inc    taklev            ; pretend that we are in Take file
  1659.     call    chk250            ;** LK250 support begin
  1660.     cmp    got250,1        ;** is it installed?
  1661.     jne    kbdini0            ;** ne = no
  1662.     call    kbrest            ;** else initialize to DEC mode
  1663.     mov    si,offset kb250lst    ;** load extensions
  1664.     jmp    short kbdini1        ;** LK250 support end
  1665. kbdini0:mov     si,offset kbdinlst      ; start of list of definitions
  1666. kbdini1:mov    cl,byte ptr [si]    ; cnt field (keyword length of macro)
  1667.     xor    ch,ch
  1668.     jcxz    kbdinix            ; z = null cnt field = end of list
  1669.     inc    si            ; look at text field
  1670.     mov    di,offset tranbuf    ; where defkey expects text
  1671.     cld
  1672.     rep    movsb            ; copy cx chars to tranbuf
  1673.     mov    byte ptr [di],0        ; insert null terminator
  1674.     inc    si            ; skip '$' field
  1675.     mov    ax,word ptr [si]    ; get value field
  1676.     mov    keycode,ax        ; set key ident value
  1677.     push    si
  1678.     call    dfkey2            ; put dfkey to work
  1679.     pop    si
  1680.     add    si,2            ; point to next entry
  1681.     jmp    kbdini1            ; keep working
  1682. kbdinix:dec    taklev            ; reset Take file level
  1683.     call    udkclear        ; clear User Definable Keys
  1684.     ret
  1685. kbdinit    endp
  1686. ;;;    End of System Independent Procedures
  1687.  
  1688. ;;;    Begin System Dependent Procedures
  1689.  
  1690. ; Read keyboard. System dependent.
  1691. ; Return carry set if nothing at keyboard.
  1692. ; If char present return carry clear with key's code in Keycode.
  1693. ; If key is ascii put that in the low byte of Keycode and clear bit Scan in
  1694. ; the high byte; otherwise, put the scan code in the lower byte and set bit
  1695. ; Scan in the high byte.
  1696. ; Bit Scan is set if key is not an ascii code.
  1697. ; Two methods are used: Bios reading for Set Key ON, and DOS reading for
  1698. ; Set Key OFF. DOS scan codes are coerced to Bios values as much as possible.
  1699. ; Modifies register ax.
  1700. getkey    proc    near
  1701.     mov    keycode,0        ; clear old keycode
  1702.     cmp    dosflg,0        ; do DOS keyboard reading?
  1703.     jne    getky7            ; ne = yes, DOS
  1704.     jmp    getky6            ; do full Bios form
  1705.                     ; ;;;;;;;; D O S ;;;;;;;;;;
  1706. getky7:    test    byte ptr kbcodes,80h    ; kbcodes initiated?        [dan]
  1707.     jz    getky5            ; z = yes            [dan]
  1708.     push    si
  1709.     call    nrc2cp            ; point SI at this code page to NRC
  1710.     mov    nrcptr,si
  1711.     pop    si
  1712.     push    bx
  1713.     call    cplatin            ; code page to Latin1, BX gets ptr
  1714.     mov    latinptr,bx
  1715.     call    cpdecsg            ; code page to DEC-MCS, BX gets ptr
  1716.     mov    decmnptr,bx
  1717.     pop    bx
  1718.     and    byte ptr kbcodes,not 80h ; say kbcodes initiated
  1719. getky5:    call    iseof            ; is stdin at eof?
  1720.     jnc    getky5k            ; nc = not eof, get more
  1721.      mov    al,trans.escchr        ; Kermit's escape char
  1722.     mov    byte ptr keycode,al    ; save ascii char
  1723.     clc                ;  to get out gracefully at EOF
  1724.     ret                ; and exit
  1725.  
  1726. getky5k:mov    dl,0ffh            ; DOS read operation
  1727.     mov    ah,dconio        ; from stdin
  1728.     int    dos
  1729.     jnz    getky5a            ; nz = char available
  1730.     stc                ; carry set = nothing available
  1731.     ret                ; exit on no char
  1732. getky5a:cmp    al,0            ; scan code precursor?
  1733.     je    getky5d            ; e = yes
  1734.     cmp    al,16            ; Control P?
  1735.     jne    getky5b            ; ne = no
  1736.     mov    al,114            ; force Control PrtSc scan code
  1737.     jmp    short getky5e        ; process as scan code
  1738. getky5b:cmp    al,BS            ; backspace key?
  1739.     jne    getky5c            ; ne = no
  1740.     mov    al,14            ; force scan code for BS key
  1741.     jmp    short getky5e        ; process as scan code
  1742. getky5c:mov    byte ptr keycode,al    ; save ascii char
  1743.     clc                ; carry clear = got a char
  1744.     ret                ; and exit
  1745.  
  1746. getky5d:mov    dl,0ffh            ; read second byte (actual scan code)
  1747.     mov    ah,dconio        ; read via DOS
  1748.     int    dos
  1749.     jnz    getky5e            ; nz = got a char
  1750.     stc                ; none, declare bad read
  1751.     ret
  1752.                     ; Check and modify to Bios scan codes
  1753. getky5e:mov    byte ptr keycode,al    ; save char code
  1754.     cmp    al,1            ; Alt escape
  1755.     je    getkya            ; set Alt bit
  1756.     cmp    al,16            ; back tab
  1757.     jb    getky5g            ; these remain unchanged
  1758.     cmp    al,50            ; start of meta keys
  1759.     jb    getkya            ; b = set Alt bit
  1760.     cmp    al,84            ; Shift F1
  1761.     jb    getky5g            ; b = no change
  1762.     cmp    al,94            ; Control F1
  1763.     jb    getkys            ; set Shift bit
  1764.     cmp    al,104            ; Alt F1
  1765.     jb    getkyc            ; set Control bit
  1766.     cmp    al,114            ; Control PrtSc
  1767.     jb    getkya            ; set Alt bit
  1768.     cmp    al,120            ; Alt top rank
  1769.     jb    getkyc            ; set Control bit
  1770.     cmp    al,132            ; Control PgUp
  1771.     jb    getkya            ; set Alt bit
  1772.     je    getkyc            ; set Control bit
  1773.     cmp    al,135            ; Shift F11, for Enhanced keyboard
  1774.     jb    getky5g            ; no change
  1775.     cmp    al,137            ; Control F11
  1776.     jb    getkys            ; set Shift bit
  1777.     cmp    al,139            ; Alt F11
  1778.     jb    getky5c            ; set Control bit
  1779.     cmp    al,141            ; Control Up
  1780.     jb    getkya            ; set Alt bit
  1781.     cmp    al,151            ; Alt Home
  1782.     jb    getkyc            ; set Control bit
  1783.     jmp    short getkya        ; set Alt bit
  1784. getkyc:    or    keycode,control        ; set Control bit
  1785.     jmp    short getky5g
  1786. getkys:    or    keycode,shift        ; set Shift bit
  1787.     jmp    short getky5g
  1788. getkya:    or    keycode,alt        ; set Alt bit
  1789. getky5g:or    keycode,scan        ; ensure scan bit is set
  1790.     clc                ; report we have a scan keycode
  1791.     ret                ; and exit
  1792.  
  1793.                     ; ;;;;;;;;;; B I O S ;;;;;;;;;;;;;
  1794. getky6:                    ; full BIOS keyboard reading
  1795.     test    byte ptr kbcodes,80h    ; kbcodes initiated?        [dan]
  1796.     jz    getky6a            ; z = yes            [dan]
  1797.     mov    kbcodes,0001h        ; low byte = status, high = read char
  1798.     push    cx            ; save registers
  1799.     push    es
  1800.     mov    cx,40h            ; segment 40h
  1801.     mov    es,cx
  1802.     mov    cl,byte ptr es:[96h]    ; kbd_flag_3, Enhanced keyboard area
  1803.     and    cl,10h            ; select Enhanced kbd presence bit
  1804.     mov    ch,cl            ; copy, for both status and read
  1805.     or    kbcodes,cx        ; 0 = regular kbd, 10h = enhanced kbd
  1806.     pop    es
  1807.     pop    cx
  1808.     push    si
  1809.     call    nrc2cp            ; point SI at this code page to NRC
  1810.     mov    nrcptr,si
  1811.     pop    si
  1812.     push    bx
  1813.     call    cplatin            ; code page to Latin1, BX gets ptr
  1814.     mov    latinptr,bx
  1815.     call    cpdecsg            ; code page to DEC-MCS, BX gets ptr
  1816.     mov    decmnptr,bx
  1817.     pop    bx
  1818.  
  1819. getky6a:mov    ah,byte ptr kbcodes    ; anything at keyboard?
  1820.     xor    al,al
  1821.     int    kbint            ; Bios keyboard interrupt
  1822.     jnz    getky1            ; nz = char available
  1823.     cmp    al,240            ; Bios "special ascii code" 0f0h?
  1824.     je    getky1            ; e = yes, Bios makes error, is a key
  1825.     stc                ; carry set = nothing available
  1826.     ret                 ; exit on no char available
  1827. getky1:    mov    ah,byte ptr kbcodes+1    ; read, no echo, wait til done
  1828.     int    kbint            ; ==> ah = scan code, al = char value
  1829.     cmp    ah,0            ; keycode entered by ALT ###?
  1830.     je    getky1c            ; e = yes, not enhanced
  1831.     cmp    ah,0e0h            ; Enhanced kbd Enter, fwd slash keys?
  1832.     jne    getky1b            ; ne = no
  1833.     xchg    ah,al            ; interchange scan and ascii fields
  1834. getky1b:cmp    al,0E0h            ; enhanced key hidden code?
  1835.     jne    getky1c            ; ne = no
  1836.     mov    byte ptr keycode,ah    ; retain scan code, supress 0e0h
  1837.     or    keycode,scan+enhanced    ; set scan and enhanced idents
  1838.     mov    ah,2            ; use regular keyboard op code here
  1839.     int    kbint            ; get current shift state
  1840.     mov    bl,al            ; copy for a moment
  1841.     and    bl,rgt_shift        ; mask out all but right shift
  1842.     shl    bl,1            ; move right shift to left shift pos
  1843.     or    al,bl            ; collapse shift bits
  1844.     and    al,(lft_shift + alt_shift + ctl_shift)
  1845.     or    byte ptr keycode+1,al    ; store in type field of keycode
  1846.     clc                ; say have a keystroke
  1847.     jmp    getkyx            ; Enhanced kbd end. Skip other tests
  1848.  
  1849. getky1c:push    cx
  1850.     mov    cx,aliaslen        ; number of aliased keys
  1851.     or    cx,cx
  1852.     pop    cx
  1853.     jz    getky2            ; z = none
  1854.     push    di            ; check key (ax) for aliases
  1855.     push    cx
  1856.     push    es
  1857.     push    ds
  1858.     pop    es            ; make es:di refer to data segment
  1859.     mov    di,offset aliaskey    ; list of aliased keys
  1860.     mov    cx,aliaslen        ; number of entries
  1861.     cld
  1862.     repne    scasw            ; look for a match
  1863.     pop    es
  1864.     pop    cx
  1865.     pop    di
  1866.     jne    getky2            ; ne = not there
  1867.     mov    al,0            ; force use of scan code (in ah)
  1868. getky2:    or    al,al            ; scan code being returned?
  1869.     jnz    getky3            ; nz = no
  1870.     mov    byte ptr keycode,ah    ; store scan code for gsh
  1871.     push    ax
  1872.     push    bx
  1873.     call    gsh            ; get modified shift state
  1874.     or    byte ptr keycode+1,al    ; store in type field of keycode
  1875.     pop    bx
  1876.     pop    ax
  1877.     xchg    ah,al            ; put scan code in al
  1878.     or    keycode,scan        ; set scan flag (vs ascii)
  1879. getky3:    mov    byte ptr keycode,al    ; return key's code (usually ascii)
  1880.     clc                ; carry clear = got a char
  1881. getkyx:    ret
  1882. getkey    endp
  1883.  
  1884. ; Return modified char code, depending on SET TERM CHAR-SET and active
  1885. ; Code Page. Enter and exit with char in AL.
  1886. xltkey    proc    near
  1887.     cmp    flags.xltkbd,0        ; keyboard translation is off?
  1888.     je    xltkey2            ; e = yes
  1889.     cmp    vtemu.vtchset,0        ; NRC's, using ASCII already?
  1890.     je    xltkey2            ; e = yes, use char in AL
  1891.     cmp    vtemu.vtchset,12    ; 1-12 for NCRs?
  1892.     ja    xltkey3            ; a = no
  1893.     push    si
  1894.     push    di
  1895.     push    ax
  1896.     mov    si,nrcptr        ; point SI at this code page to NRC
  1897.     pop    ax
  1898.     mov    di,si            ; start of table are ASCII chars
  1899.     mov    cl,vtemu.vtchset    ; get set number (1-12)
  1900.     xor    ch,ch
  1901.     sub    di,cx            ; minus one byte per set
  1902.     shl    cx,1            ; 15 bytes per NRC entry
  1903.     shl    cx,1
  1904.     shl    cx,1
  1905.     shl    cx,1
  1906.     add    di,cx            ; +16, source, point at this entry
  1907.     mov    cx,12            ; do first 12 bytes of them
  1908.     push    es
  1909.     push    ds
  1910.     pop    es
  1911.     cld
  1912.     repne    scasb            ; look for this byte code in table
  1913.     pop    es
  1914.     jne    xltkey1            ; ne = not found, use char in AL
  1915.     inc    cx
  1916.     sub    cx,12            ; compute char index
  1917.     neg    cx
  1918.     add    si,cx            ; index into ASCII table
  1919.     mov    al,[si]            ; get matching ASCII char (set 0)
  1920. xltkey1:pop    di
  1921.     pop    si
  1922. xltkey2:ret
  1923.                     ; LATIN1 set
  1924. xltkey3:test    al,80h            ; high bit set?
  1925.     jz    xltkey2            ; z = no, no translation
  1926.     cmp    vtemu.vtchset,15    ; set term character-set LATIN1?
  1927.     jne    xltkey4            ; ne = no
  1928.     and    al,not 80h        ; remove high bit
  1929.     push    bx
  1930.     mov    bx,latinptr        ; Code Page to Latin1
  1931.     xlatb                ; translate to Latin1 in AL
  1932.     pop    bx
  1933.     ret
  1934. xltkey4:cmp    vtemu.vtchset,16    ; set term character-set DEC-MCS?
  1935.     jne    xltkey2            ; ne = no
  1936.     and    al,not 80h        ; remove high bit
  1937.     push    bx
  1938.     mov    bx,DECmnptr        ; Code Page to DEC-MCS
  1939.     xlatb                ; translate to DEC-MCS in AL
  1940.     pop    bx
  1941.     ret
  1942. xltkey    endp
  1943.  
  1944. ; get shift state into al.  We care about only shift, ctl, and alt keys.
  1945. ; right shift is collapsed into left shift. NumLock offsets Shift on keypad
  1946. ; white keys.
  1947. gsh    proc    near
  1948.     mov    ah,2
  1949.     int    kbint            ; get current shift state
  1950.     mov    bl,al            ; copy for a moment
  1951.     and    bl,rgt_shift        ; mask out all but right shift
  1952.     shl    bl,1            ; move right shift to left shift pos
  1953.     or    al,bl            ; collapse shift bits
  1954.     cmp    byte ptr keycode,71    ; below numeric key pad?
  1955.     jb    gsh1            ; b = yes
  1956.     cmp    byte ptr keycode,83    ; above numeric key pad?
  1957.     ja    gsh1            ; a = yes
  1958.     cmp    byte ptr keycode,74    ; grey - key ?
  1959.     je    gsh1            ; e = yes
  1960.     cmp    byte ptr keycode,78    ; grey + key
  1961.     je    gsh1            ; e = yes
  1962.     test    al,numlock        ; numlock set?
  1963.     jz    gsh1            ; z = no
  1964.     xor    al,lft_shift        ; numlock offsets shift and vice versa
  1965. gsh1:    and    al,(lft_shift + alt_shift + ctl_shift)
  1966.     ret
  1967. gsh    endp
  1968.  
  1969.  
  1970. ; Do any local processing after reading a key during active translation
  1971. ; Avoids same actions if a key is being defined or shown.
  1972. postkey    proc    near
  1973.                     ; Key Click code for VT102 emulator
  1974.     cmp    flags.vtflg,0        ; emulating? (0 = no)
  1975.     je    postke1            ; e = extra clicks not available
  1976.     test    vtemu.vtflgst,vskeyclick ; flags from SET TERM
  1977.     jz    postke1            ; z = extra clicks not wanted
  1978.     call    vclick            ; click, what else?
  1979. postke1:ret
  1980. postkey    endp
  1981.  
  1982.                     ;** start of LK250 stuff
  1983. chk250    proc    near            ; presence test for DEC LK250 keyboard
  1984.     mov    got250,0        ; assume no LK250 keyboard
  1985.     mov    ax,5000h        ; see if the keyboard is loaded
  1986.     int    15h            ; look for DOS->DEC mode driver
  1987.     cmp    ax,1234h        ; find marker 1234h
  1988.     jne    chk250x            ; ne = marker not present, no driver
  1989.     mov    got250,1        ; else say we have an LK250
  1990. chk250x:ret
  1991. chk250    endp
  1992.  
  1993. kbrest    proc    near            ; set LK250 to DEC mode
  1994.     cmp    got250,1        ; LK250 present?
  1995.     jne    kbrest1            ; ne = no
  1996.     push    es            ; save reg
  1997.     mov    ax,40h            ; point to low memory
  1998.     mov    es,ax
  1999.     or    byte ptr es:[17h],20h    ; ensure Num Lock is on
  2000.     and    byte ptr es:[17h],0efh    ;  and Scroll is off
  2001.     pop    es            ; restore our [DS]
  2002.     mov    ax,5001h        ; issue set mode DEC to keyboard
  2003.     int    15h
  2004. kbrest1:ret
  2005. kbrest    endp
  2006.  
  2007. kbsusp    proc    near            ; set LK250 to DOS mode
  2008.     cmp    got250,1        ; LK250 present?
  2009.     jne    kbsusp1            ; ne = no
  2010.     mov    ax,5000h        ; unload extensions
  2011.     int    15h
  2012. kbsusp1:ret
  2013. kbsusp    endp
  2014.  
  2015. kbhold    proc    near
  2016.     cmp    got250,1        ; LK250 present?
  2017.     jne    kbhold1            ; ne = no
  2018.     mov    ax,5002h        ; issue SET LEDS
  2019.     mov    bl,0edh
  2020.     int    15h
  2021.     mov    ax,5002h
  2022.     mov    bl,holdscr        ; get the hold state
  2023.     or    bl,2            ; OR in Num Lock
  2024.     int    15h
  2025. kbhold1:ret
  2026. kbhold    endp                ;** end of LK250 stuff
  2027. code    ends
  2028.     end
  2029.