NAME msuibm ; File MSUIBM.ASM include mssdef.h ; Copyright (C) 1982, 1997, Trustees of Columbia University in the ; City of New York. The MS-DOS Kermit software may not be, in whole ; or in part, licensed or sold for profit as a software product itself, ; nor may it be included in or distributed with commercial products ; or otherwise distributed by commercial concerns to their clients ; or customers without written permission of the Office of Kermit ; Development and Distribution, Columbia University. This copyright ; notice must not be removed, altered, or obscured. ; Keyboard translator, by Joe R. Doupnik, Dec 1986 ; with contributions from David L. Knoell. ; Edit history ; 12 Jan 1995 version 3.14 ; Last edit ; 12 Jan 1995 public keybd, dfkey, shkey, msuinit, kbcodes public kbsusp, kbrest, kbhold ;** LK250 support for IBM-PCs public saveuoff, saveulen ; some definitions kbint equ 16h ; IBM, Bios keyboard interrupt shift equ 200h ; IBM, synonym for right or left shift control equ 400h ; IBM, synonym for control shift alt equ 800h ; IBM, synonym for alt shift enhanced equ 1000h ; IBM, enhanced keyboard code rgt_shift equ 1 ; IBM shift state bits lft_shift equ 2 ctl_shift equ 4 alt_shift equ 8 numlock equ 20h maxkeys equ 350 ; maximum number of key definitions maxstng equ 256 ; maximum number of multi-char strings stbuflen equ 2000 ; length of string buffer (bytes) verb equ 8000h ; dirlist flag: use verb action table strng equ 4000h ; dirlist flag: use string action table scan equ 100h ; keycode flag: code is scan not ascii braceop equ 7bh ; opening curly brace bracecl equ 7dh ; closing curly brace data segment extrn taklev:byte, comand:byte, flags:byte, keyboard:word extrn shkadr:word, stkadr:word, trans:byte, ttyact:byte ; system dependent references extrn vtemu:byte, holdscr:byte ; emulator data extrn vtmacname:word, vtmaclen:word ; external macro, in msyibm extrn isps55:byte ; [HF]940130 in MSXIBM.ASM extrn ps55mod:byte ; [HF]940206 in MSXIBM.ASM extrn domath_ptr:word, domath_cnt:word, termesc_flag:byte ;;; System Independent local storage crlf db cr,lf,'$' dfaskky db cr,lf,' Push key to be defined: $' dfaskdf db ' Enter new definition: ',0 ; asciiz for prompt strbad db cr,lf,' Not enough space for new string',cr,lf,'$' keyfull db cr,lf,' No more space to define keys',cr,lf,'$' dfkoops db cr,lf,' Oops! That is Kermit',27h,'s Escape Char.' db ' Translation is not permitted.',cr,lf,'$' shkmsg1 db cr,lf,'Push key to be shown (? shows all): $' shkmsg2 db ' decimal is defined as',cr,lf,'$' shkmsg3 db cr,lf,'... more, press a key to continue ...$' kwarnmsg db cr,lf,' Notice: this form of Set Key is obsolete$' ascmsg db ' Ascii char: $' scanmsg db ' Scan Code $' strngmsg db ' String: $' verbmsg db ' Verb: $' noxmsg db ' Self, no translation.$' fremsg db cr,lf,' Free space: $' kyfrdef db ' key and $' stfrdef db ' string definitions, $' stfrspc db ' string characters.',cr,lf,'$' even saveuoff label word ; per session save area start tranbuf db 150 dup (?) ; 150 byte translator work buffer db 0 ; guard for overflow by one ; translation tables keylist dw maxkeys dup (0) ; 16 bit keycodes, paralled by dirlist dirlist dw maxkeys dup (0) ; director {v+s} + {index | new char} sptable dw maxstng dup (0) ; list of asciiz string offsets stbuf dw stbuflen dup (0) ; buffer for strings strmax dw stbuf ; first free byte in stbuf stringcnt dw 0 ; qty of string chars to be processed stringptr dw 0 ; address of next string char nkeys dw 0 ; number of actively defined keys listptr dw 0 ; item number for keylist and dirlist keycode dw 0 ; ascii/scan code for key kbtemp dw 0 ; scratch storage for translator brace db 0 ; brace detected flag byte msutake db 0 ; if being run from take file or not verblen dw 0 ; length of user's verb (work temp) kwcnt dw 0 ; number of keywords (work temp) dosflg db 0 saveulen dw ($ - saveuoff) ; save area end oldform db 0 ; old form Set Key, if non-zero eleven dw 11d ; [HF]940211 twelve dw 12d ;;; End System Independent Data Area ; Aliaskey: keys having aliases - same ascii code but more than one ; scan code, as on auxillary keypads. Use just scan codes with these. ; Alternative use: force ascii keys to report out just scan codes. ; Table format: high byte = scan code, low byte = ascii code. ; Contents are machine dependent. aliaskey dw (14*scan)+bs ; Backspace key [hi=scan, lo=ascii] dw (55*scan)+'*' ; keypad asterisk dw (74*scan)+'-' ; keypad minus dw (78*scan)+'+' ; keypad plus dw (71*scan)+'7' ; keypad numeric area dw (72*scan)+'8' dw (73*scan)+'9' dw (75*scan)+'4' dw (76*scan)+'5' dw (77*scan)+'6' dw (79*scan)+'1' dw (80*scan)+'2' dw (81*scan)+'3' dw (82*scan)+'0' dw (83*scan)+'.' dw (83*scan)+',' ; German keypad had comma vs dot dw (15*scan)+tab dw (28*scan)+cr ; typewriter Enter key dw (28*scan)+lf ; typewriter Control-Enter dw (57*scan)+' ' ; space bar dw (01*scan)+1bh ; Esc key aliaslen equ ($-aliaskey) shr 1 ; number of words in aliaskey table ifndef no_network kverbs db 163 ; number of table entries below else ifndef no_tcp kverbs db 163 - 3 ; number of table entries below else kverbs db 163 - 4 ; number of table entries below endif ; no_tcp endif ; no_network mkeyw 'uparr',uparrw ; independent of ordering and case! mkeyw 'dnarr',dnarrw ; mkeyw 'name',procedure entry point mkeyw 'lfarr',lfarr mkeyw 'rtarr',rtarr mkeyw 'Gold',pf1 mkeyw 'PF1',pf1 mkeyw 'PF2',pf2 mkeyw 'PF3',pf3 mkeyw 'PF4',pf4 mkeyw 'KP0',kp0 mkeyw 'KP1',kp1 mkeyw 'KP2',kp2 mkeyw 'KP3',kp3 mkeyw 'KP4',kp4 mkeyw 'KP5',kp5 mkeyw 'KP6',kp6 mkeyw 'KP7',kp7 mkeyw 'KP8',kp8 mkeyw 'KP9',kp9 mkeyw 'kpminus',kpminus mkeyw 'kpcoma',kpcoma mkeyw 'kpenter',kpenter mkeyw 'kpdot',kpdot mkeyw 'decF6',decf6 mkeyw 'decF7',decf7 mkeyw 'decF8',decf8 mkeyw 'decF9',decf9 mkeyw 'decF10',decf10 mkeyw 'decF11',decf11 mkeyw 'decF12',decf12 mkeyw 'decF13',decf13 mkeyw 'decF14',decf14 mkeyw 'decHelp',dechelp mkeyw 'decDo',decdo mkeyw 'decF17',decf17 mkeyw 'decF18',decf18 mkeyw 'decF19',decf19 mkeyw 'decF20',decf20 mkeyw 'decFind',decfind mkeyw 'decInsert',decinsert mkeyw 'decRemove',decremove mkeyw 'decSelect',decselect mkeyw 'decPrev',decprev mkeyw 'decNext',decnext mkeyw 'udkF6',udkf6 mkeyw 'udkF7',udkf7 mkeyw 'udkF8',udkf8 mkeyw 'udkF9',udkf9 mkeyw 'udkF10',udkf10 mkeyw 'udkF11',udkf11 mkeyw 'udkF12',udkf12 mkeyw 'udkF13',udkf13 mkeyw 'udkF14',udkf14 mkeyw 'udkF15',udkf15 mkeyw 'udkF16',udkf16 mkeyw 'udkF17',udkf17 mkeyw 'udkF18',udkf18 mkeyw 'udkF19',udkf19 mkeyw 'udkF20',udkf20 mkeyw 'Compose',kbdcompose mkeyw 'termtype',vtans52 mkeyw 'reset',vtinit mkeyw 'holdscrn',khold mkeyw 'dnscn',dnwpg mkeyw 'upscn',upwpg mkeyw 'endscn',endwnd mkeyw 'homscn',homwnd mkeyw 'upone',upone mkeyw 'dnone',dnone mkeyw 'prtscn',trnprs mkeyw 'dump',dmpscn mkeyw 'modeline',trnmod mkeyw 'break',sendbr mkeyw 'lbreak',sendbl mkeyw 'hangup',chang mkeyw 'debug',kdebug ifndef no_network mkeyw 'nethold',ubhold endif ; no_network ifndef no_tcp mkeyw 'tn_AYT',tn_AYT mkeyw 'tn_IP',tn_IP mkeyw 'nextsession',nextses mkeyw 'session1',ses1 mkeyw 'session2',ses2 mkeyw 'session3',ses3 mkeyw 'session4',ses4 mkeyw 'session5',ses5 mkeyw 'session6',ses6 endif ; no_tcp mkeyw 'null',snull mkeyw 'logon',klogon mkeyw 'logoff',klogof mkeyw 'DOS',cdos mkeyw 'help',cquery mkeyw 'status',cstatus mkeyw 'exit',cquit mkeyw 'lfpage',lfpage mkeyw 'rtpage',rtpage mkeyw 'lfone',lfone mkeyw 'rtone',rtone mkeyw 'dgC1',dgkc1 mkeyw 'dgC2',dgkc2 mkeyw 'dgC3',dgkc3 mkeyw 'dgC4',dgkc4 mkeyw 'dgF1',dgkf1 mkeyw 'dgF2',dgkf2 mkeyw 'dgF3',dgkf3 mkeyw 'dgF4',dgkf4 mkeyw 'dgF5',dgkf5 mkeyw 'dgF6',dgkf6 mkeyw 'dgF7',dgkf7 mkeyw 'dgF8',dgkf8 mkeyw 'dgF9',dgkf9 mkeyw 'dgF10',dgkf10 mkeyw 'dgF11',dgkf11 mkeyw 'dgF12',dgkf12 mkeyw 'dgF13',dgkf13 mkeyw 'dgF14',dgkf14 mkeyw 'dgF15',dgkf15 mkeyw 'dgSF1',dgkSf1 mkeyw 'dgSF2',dgkSf2 mkeyw 'dgSF3',dgkSf3 mkeyw 'dgSF4',dgkSf4 mkeyw 'dgSF5',dgkSf5 mkeyw 'dgSF6',dgkSf6 mkeyw 'dgSF7',dgkSf7 mkeyw 'dgSF8',dgkSf8 mkeyw 'dgSF9',dgkSf9 mkeyw 'dgSF10',dgkSf10 mkeyw 'dgSF11',dgkSf11 mkeyw 'dgSF12',dgkSf12 mkeyw 'dgSF13',dgkSf13 mkeyw 'dgSF14',dgkSf14 mkeyw 'dgSF15',dgkSf15 mkeyw 'dgspcl',kbdcompose mkeyw 'dgpoint',dgpoint mkeyw 'dgnc',dgnckey mkeyw 'wyseF1',wykf1 mkeyw 'wyseF2',wykf2 mkeyw 'wyseF3',wykf3 mkeyw 'wyseF4',wykf4 mkeyw 'wyseF5',wykf5 mkeyw 'wyseF6',wykf6 mkeyw 'wyseF7',wykf7 mkeyw 'wyseF8',wykf8 mkeyw 'wyseF9',wykf9 mkeyw 'wyseF10',wykf10 mkeyw 'wyseF11',wykf11 mkeyw 'wyseF12',wykf12 mkeyw 'wyseF13',wykf13 mkeyw 'wyseF14',wykf14 mkeyw 'wyseF15',wykf15 mkeyw 'wyseF16',wykf16 mkeyw 'wyseSF1',wykSf1 mkeyw 'wyseSF2',wykSf2 mkeyw 'wyseSF3',wykSf3 mkeyw 'wyseSF4',wykSf4 mkeyw 'wyseSF5',wykSf5 mkeyw 'wyseSF6',wykSf6 mkeyw 'wyseSF7',wykSf7 mkeyw 'wyseSF8',wykSf8 mkeyw 'wyseSF9',wykSf9 mkeyw 'wyseSF10',wykSf10 mkeyw 'wyseSF11',wykSf11 mkeyw 'wyseSF12',wykSf12 mkeyw 'wyseSF13',wykSf13 mkeyw 'wyseSF14',wykSf14 mkeyw 'wyseSF15',wykSf15 mkeyw 'wyseSF16',wykSf16 mkeyw 'ignore',ignore_key ; Initialization data. kbdinlst equ this byte ; Kermit IBM initialization time keyboard setup mkeyw '\kgold',scan+59 ; F1 mkeyw 'definition',keycode mkeyw '\kpf2',scan+60 ; F2 mkeyw '\kpf3',scan+61 ; F3 mkeyw '\kpf4',scan+62 ; F4 mkeyw '\kkp0',scan+shift+90 ; VT100 keypad numeric area, SF7 mkeyw '\kkp1',scan+shift+86 ; SF3 mkeyw '\kkp2',scan+shift+87 ; SF4 mkeyw '\kkp3',scan+shift+88 ; SF5 mkeyw '\kkp4',scan+67 ; F9 mkeyw '\kkp5',scan+68 ; F10 mkeyw '\kkp6',scan+shift+84 ; SF1 mkeyw '\kkp7',scan+63 ; F5 mkeyw '\kkp8',scan+64 ; F6 mkeyw '\kkp9',scan+65 ; F7 mkeyw '\kkpenter',scan+shift+89 ; SF6 mkeyw '\kkpcoma',scan+shift+85 ; SF2 mkeyw '\kkpminus',scan+66 ; F8 mkeyw '\kkpdot',scan+shift+91 ; SF8 mkeyw '\kuparr',scan+72 ; VT100 cursor keys (arrows) mkeyw '\kdnarr',scan+80 mkeyw '\klfarr',scan+75 mkeyw '\krtarr',scan+77 mkeyw '\kupscn',scan+73 ; PgUp Kermit screen roll back keys mkeyw '\kdnscn',scan+81 ; PgDn mkeyw '\khomscn',scan+71 ; Home mkeyw '\kendscn',scan+79 ; End mkeyw '\kupone',scan+control+132 ; Ctrl PgUp one line scrolls mkeyw '\kdnone',scan+control+118 ; Ctrl PgDn mkeyw '\kuparr',scan+enhanced+72 ; Enhanced kbd duplicate keys mkeyw '\kdnarr',scan+enhanced+80 mkeyw '\klfarr',scan+enhanced+75 mkeyw '\krtarr',scan+enhanced+77 mkeyw '\kupscn',scan+enhanced+73 ; PgUp Kermit screen roll back keys mkeyw '\kdnscn',scan+enhanced+81 ; PgDn mkeyw '\khomscn',scan+enhanced+71 ; Home mkeyw '\kendscn',scan+enhanced+79 ; End mkeyw '\kupone',scan+control+enhanced+132 ;Ctrl PgUp one line scroll mkeyw '\kdnone',scan+control+enhanced+118 ; Ctrl PgDn mkeyw '\kmodeline',scan+74 ; Kermit toggle mode line Keypad - mkeyw '\ktermtype',scan+alt+130 ; Kermit toggle terminal type Alt - mkeyw '\kreset',scan+alt+131 ; Kermit reset terminal Alt = mkeyw '\kreset',scan+alt+19 ; ALT r for reset too mkeyw '\kdebug',scan+alt+32 ; ALT d for debug mkeyw '\kprtscn',scan+control+114 ; Kermit toggle prn scrn Ctrl * mkeyw '\kdump',scan+control+117 ; Kermit Dump Screen Ctrl End mkeyw '*',scan+55 ; keypad asterisk mkeyw '*',scan+enhanced+55 ; Enhanced kbd keypad asterisk mkeyw '+',scan+78 ; keypad plus mkeyw '.',scan+shift+83 ; IBM numeric keypad mkeyw '0',scan+shift+82 mkeyw '1',scan+shift+79 mkeyw '2',scan+shift+80 mkeyw '3',scan+shift+81 mkeyw '4',scan+shift+75 mkeyw '5',scan+shift+76 mkeyw '6',scan+shift+77 mkeyw '7',scan+shift+71 mkeyw '8',scan+shift+72 mkeyw '9',scan+shift+73 mkeyw ' ',scan+57 ; space bar yields space mkeyw ' ',scan+shift+57 ; Shift + space bar mkeyw '\0',scan+control+57 ; Control-space bar yields nul mkeyw '\0',scan+control+shift+57; Shift Control-space bar mkeyw tab,scan+15 ; regular Tab key, made special mkeyw cr,scan+28 ; typewriter Enter key mkeyw cr,scan+enhanced+cr ; Enhanced kbd grey Enter key mkeyw lf,scan+control+28 ; Control-Enter mkeyw lf,scan+enhanced+control+lf ; Enhanced grey Control Enter mkeyw '/',scan+enhanced+'/' ; Enhanced kbd grey foward slash mkeyw '\0',scan+control+3 ; Control at-sign sends null mkeyw '\0',scan+control+shift+3 ; Control Shift at-sign sends null mkeyw '\x7f',scan+83 ; Del key sends DEL mkeyw '\x7f',scan+enhanced+83 ; Enhanced duplicate DEL sends DEL mkeyw '\x7f',scan+14 ; Backspace key sends DEL mkeyw '\x1b',scan+01 ; Esc key sends ESC mkeyw '\kexit',scan+alt+45 ; Exit connect mode Alt X mkeyw '\kstatus',scan+alt+31 ; Connect mode status Alt S mkeyw '\kbreak',scan+alt+48 ; Send a Break Alt B mkeyw '\kbreak',scan+control+0; Control-Break sends a Break too mkeyw '\khelp',scan+alt+35 ; Connect mode drop down menu Alt H mkeyw '\kcompose',scan+alt+46 ; ALT C is compose ifndef no_tcp mkeyw '\knextsession',scan+alt+49 ; nextses is Alt N mkeyw '\knethold',scan+alt+44 ; ALT Z is nethold endif ; no_tcp dw 0 ; end of table marker ;** LK250 support begin kb250lst equ this byte ; Extensions for DEC LK250 keyboard mkeyw escape,scan+104 ; Compose maps to ESC mkeyw '\x7f',scan+14 ; Backspace key sends DEL mkeyw bs,scan+shift+14 ; Shift-Backspace key sends BS mkeyw cr,scan+28 ; Return key sends CR mkeyw lf,scan+shift+28 ; Shift-Return sends LF mkeyw tab,scan+15 ; Tab sends TAB ; the top-row function keys mkeyw '\kholdscrn',scan+59 ; DEC Hold mkeyw '\kprtscn',scan+60 ; DEC Print Screen ;;;; mkeyw '{\{kstatus}\{kexit}}',scan+61 ; DEC Set-Up mkeyw '\kbreak',scan+63 ; DEC Break mkeyw '\kdecF6',scan+64 ; DEC F6 mkeyw '\kdecF7',scan+65 ; DEC F7 mkeyw '\kdecF8',scan+66 ; DEC F8 mkeyw '\kdecF9',scan+67 ; DEC F9 mkeyw '\kdecF10',scan+68 ; DEC F10 mkeyw '\kdecF11',scan+95 ; DEC F11 mkeyw '\kdecF12',scan+96 ; DEC F12 mkeyw '\kdecF13',scan+97 ; DEC F13 mkeyw '\kdecF14',scan+98 ; DEC F14 mkeyw '\kdecHelp',scan+99 ; DEC Help mkeyw '\kdecDo',scan+100 ; DEC DO mkeyw '\kdecF17',scan+101 ; DEC F17 mkeyw '\kdecF18',scan+102 ; DEC F18 mkeyw '\kdecF19',scan+103 ; DEC F19 mkeyw '\kdecF20',scan+84 ; DEC F20 ; the cursor/select cluster mkeyw '\kdecFind',scan+85 ; DEC Find mkeyw '\kdecInsert',scan+86 ; DEC Insert Here mkeyw '\kdecRemove',scan+87 ; DEC Remove mkeyw '\kdecSelect',scan+88 ; DEC Select mkeyw '\kdecPrev',scan+89 ; DEC Prev mkeyw '\kdecNext',scan+90 ; DEC Next mkeyw '\kuparr',scan+91 ; up arrow mkeyw '\klfarr',scan+92 ; left arrow mkeyw '\krtarr',scan+93 ; right arrow mkeyw '\kdnarr',scan+94 ; down arrow ; the DEC editing keypad mkeyw '\kgold',scan+106 ; F1 mkeyw '\kpf2',scan+107 ; F2 mkeyw '\kpf3',scan+108 ; F3 mkeyw '\kpf4',scan+109 ; F4 mkeyw '\kkp7',scan+shift+71 ; KP7 mkeyw '\kkp8',scan+shift+72 ; KP8 mkeyw '\kkp9',scan+shift+73 ; KP9 mkeyw '\kkpminus',scan+74 ; KP- mkeyw '\kkp4',scan+shift+75 ; KP4 mkeyw '\kkp5',scan+shift+76 ; KP5 mkeyw '\kkp6',scan+shift+77 ; KP6 mkeyw '\kkpcoma',scan+78 ; KP, mkeyw '\kkp1',scan+shift+79 ; KP1 mkeyw '\kkp2',scan+shift+80 ; KP2 mkeyw '\kkp3',scan+shift+81 ; KP3 mkeyw '\kkpenter',scan+105 ; keypad enter mkeyw '\kkpenter',scan+shift+105 ; keypad enter mkeyw '\kkp0',scan+shift+82 ; KP0 mkeyw '\kkpdot',scan+shift+83 ; KP. ; some useful Kermit keys mkeyw '\kupscn',scan+alt+89 ; PgUp Kermit screen roll back keys mkeyw '\kdnscn',scan+alt+90 ; PgDn mkeyw '\khomscn',scan+alt+85 ; Home mkeyw '\kendscn',scan+alt+88 ; End mkeyw '\kupone',scan+control+89 ; Ctrl PgUp one line scrolls mkeyw '\kdnone',scan+control+90 ; Ctrl PgDn mkeyw '\kexit',scan+alt+45 ; Exit connect mode Alt X mkeyw '\kstatus',scan+alt+31 ; Connect mode status Alt S mkeyw '\kbreak',scan+alt+48 ; Send a Break Alt B mkeyw '\kbreak',scan+control+108 ; Control-Break sends a Break too mkeyw '\khelp',scan+alt+35 ; Connect mode drop down menu Alt H mkeyw '\ktermtype',scan+alt+130 ; Kermit toggle terminal type Alt - mkeyw '\kreset',scan+alt+131 ; Kermit reset terminal Alt = mkeyw '\kprtscn',scan+control+109 ; Kermit toggle prn scrn Ctrl * mkeyw '\kdump',scan+control+88 ; Kermit Dump Screen Ctrl End dw 0 ; end of table marker got250 db 0 ;** LK250 present if non-zero kbd250 db 0 ; enable use of LK250 if non-zero lk250msg db cr,lf,'?LK250 keyboard external driver is not active.$' ;** LK250 support end kbcodes dw 80h ; keyboard read codes, 80h=not inited data ends data1 segment dfhelp1 db cr,lf,' Enter key',27h,'s identification as a character',cr,lf db ' or as its numerical equivalent \{b##} of ascii',cr,lf db ' or as its scan code \{b##}' db cr,lf,' or as SCAN followed by its scan code',cr,lf db ' where b is O for octal, X for hex, or D for decimal' db ' (default).',cr,lf,' Braces {} are optional.' db cr,lf,' Follow the identification with the new definition.' db cr,lf,' or CLEAR to restore initial key settings' db cr,lf,' or ON (default) for Bios i/o or OFF to use DOS i/o' db cr,lf,' or LK to use the DEC LK250 keyboard.$' ;IBM ;;; System Dependent Data Area ; edit dfhelp2 to include nice list of verbs for this system. dfhelp2 db cr,lf,' Enter either \Kverb for a Kermit action verb',cr,lf db ' or a replacement string (single byte binary numbers are' db ' \{b##})',cr,lf,' or push Return to undefine a key, ^C to' db ' retain current definition.' db cr,lf,' Braces {} are optional, and strings maybe enclosed in' db ' them.',cr,lf,' Strings may not begin with the character' db ' combinations of \k or \{k',cr,lf db ' (start with a { brace instead).',cr,lf,lf db ' Verbs are as follows. Keys (arrows and keypad):',cr,lf db ' uparr, dnarr, lfarr, rtarr, kpminus, kpcoma, kpdot, kpenter,' db cr,lf db ' Gold (same as PF1), PF1, PF2, PF3, PF4, kp0, ... kp9' db cr,lf,' decFind, decInsert, decRemove, decSelect, decPrev,' db ' decNext' db cr,lf,' decF6, ...decF14, decHelp, decDO, decF17, ...decF20' db cr,lf,' Compose (same as dgSPCL)' db cr,lf,' User Definable Keys udkF6, ...udkF20' db cr,lf,' Data General dgC1..dgC4, dgF1..dgF15, dgSF1..dgSf15,' db cr,lf,' dgPoint, dgSPCL, dgNC' db cr,lf,' Wyse-50 function keys wyseF1..wyseF16, wyseSF1..' db 'wyseSF16' db cr,lf,' Kermit screen control and actions:',cr,lf db ' upscn, dnscn, homscn, endscn, upone, dnone (vertical ' db 'scrolling),' db cr,lf db ' lfpage, lfone, rtpage, rtone (horizontal scrolling)' db cr,lf db ' logoff, logon, termtype, reset, holdscrn, modeline, break,' db ' debug,' db cr,lf db ' lbreak, nethold, nextsession, prtscn, dump, hangup, null' db ' (send one),' db cr,lf ifndef no_tcp db ' session1, ..session6 (selects Telnet session number 1..6)' db cr,lf endif ; no_tcp db ' tn_AYT, tn_IP, DOS, help, ignore, status, exit' db cr,lf,'$' data1 ends ; Documentation ;Translating a key: ; The translator is called to obtain keyboard input; it sends characters to ; the serial port through standard controlled echo procedures or invokes ; named procedures. It returns carry clear when its operation is completed ; for normal actions and carry set when Connect mode must be exited. When ; Connect mode is exited the just read char should be passed in Kbdflg ; to msster.asm for invoking actions such as Status, send a break, ; quit connect mode; system dependent procedure Term is responsible for this. ; ; Principal procedures are - ; msuinit Initializes keyboard translator in this file when ; Kermit first begins. Installs dfkey and shkey as the ; procedures used for Set Key and Show Key. Sys Indep. ; Called from msx or msy init procs. System Independent. ; keybd Performs the translation, outputs chars to the serial ; port or invokes a Kermit action routine. Sys Indep. ; dfkey Defines a key's translation. Reads command line ; via Kermit's command parser comnd. System Independent. ; shkey Shows translation of a key. Requests user to push ; selected key. System Independent. ; ; kbdinit optional. Initializes the translation tables when ; Kermit starts up. Called by msuinit. System Dependent. ; getkey Performs the keyboard read and returns results in ; a standardized system independent format. Sys Depend. ; postkey called by active translator after obtaining a keycode. ; Used to provide extra local actions (keyclick) only ; in Connect mode (not during Set/Show key commands). ; Called by keybd. System dependent. ; Supporting system independent procedures are - ; shkfre (show string free space), tstkeyw (finds user's keyword in the verb ; table), insertst (insert string in buffer), remstr (delete string in buffer). ; ; System dependent procedure Getkey reads a keycode (usually via a Bios ; call). On IBM compatible machines this yields ; for ordinary keys, or for special keys such as F1, ; or when Alt### is used. ; For any system, the canonical output form is the key's code in Keycode. ; Place the ascii code (or scan code if none) in byte Keycode and ancillary ; info (shift states plus marker bit for scan codes) in byte Keycode + 1. ; ; Table Aliaskey is a list of scan code/ascii codes for keys which appear ; more than once on a keyboard. This list is examined to distinguish such ; aliased keys (those on an auxillary keypad) from an ordinary ascii key, ; and the aliased key is then referenced by its scan code rather than by ; the ordinary ascii code. Aliaskey is machine and keyboard dependent. ; ; Procedure Keybd calls Getkey for the Keycode, checks list of translatable ; keys Keylist, and then either sends an ascii string (one or more characters) ; or invokes a Kermit action verb. List Dirlist indicates what kind of ; translation to do. Keybd is system independent but may contain system ; dependent special actions such as echoing keyclicks. Keybd calls system ; dependent procedure Postkey just after calling getkey so local actions ; such as keyclicks can be activated only during Connect mode operations. ; ; Keylist is a packed but unordered list of 16 bit keycodes which need ; translation. The lower order byte holds a key code (ascii char or scan code) ; while the high byte holds a scan code marker bit (0 if ascii code in low ; byte) plus any ancillary keyboard information such as Control/Shift/Alt/Meta ; keys being held down; these are of use in Show Key presentations. ; Dirlist parallels Keylist to provide the kind of translation, verb or ; string, in the two highest bits with the other bits holding either ; a single new replacement character or the item number in lists of verbs ; or strings. If neither verb nor strng type bits are set in a dirlist ; word then the translation is a single new character held in the lower ; eight bits of that dirlist word. ; ; The number of key translations is assembly constant Maxkeys (def 128). ; The maximum number of strings is assembly constant Maxstngs (def 64). ; The maximum number of verbs is 256 and is set by building table Kverbs. ; ; For verbs, use the Item number from the Director table Dirlist to select ; a procedure offset from the structured list Kverbs and jump to that offset. ; Most verb procedures return carry clear to stay within Connect mode. ; Verbs requiring exiting Connect mode return carry set and may set byte ; Kbdflg to a char code which will be read by msster.asm for activating a ; transient Kermit action such as send a break (Kbdflg = 'b'). ; Kbdflg is stored in msster.asm (as zero initially, meaning ignore it). ; Action verb procedures are normally located in a system dependent file. ; ; For multi-char strings, use Item number from Director table Dirlist to ; select a pointer to a string. The list of string pointers is Sptable ; (string pointer table) which holds the offset in the data segment of the ; strings stored in buffer Stbuf. In stbuf strings are held as: one byte of ; length of following text and then the text itself (permits embedded nulls). ; Use Chrout to send each string character, and finally return from Keybd ; with carry clear. ; ; For single character replacements obtain the new character from the lower ; order byte of Director table Dirlist. If the character is Kermit's present ; escape character return from Keybd carry set to leave connect mode. ; Otherwise, send the character via Chrout and return from Keybd carry clear. ; Keylist table format: ; 7 bits 1 bit 8 bits ; +----------+----+------------+ scan bit = 1 if key's code is non-ascii ; | aux info |scan| key's code | aux info = system dependent, used only to ; +----------+----+------------+ help identify key ; ; Dirlist table format v s meaning ; 1 1 14 bits 0 0 copy out one byte translation ; +---+---+--------------------+ 1 0 copy out multi-char string number Item ; | v | s | item # or new char | 0 1 do action verb number Item ; +---+---+--------------------+ 1 1 (not used) ; ; Table kverbs is organized by macro mkeyw as - ; kverbs db number of table entries ; (each entry is in the form below:) ; dw number of bytes in verbname ; db 'verbname' variable length ; dw value offset of procedure ; ; ; Dfkey defines a key to be itself (undefines it) or a single replacement ; character or a character string or a Kermit action verb. Dfkey requires ; a command line so that it may be invoked by Take files but can be forced ; to prompt an interactive user to push a key. Syntax is discussed below. ; Note that redefined keys have their old definitions cleared so that ; old string space is reclaimed automatically. ; ; Shkey displays a key's definition and the user is asked to push the ; selected key. The free space for strings is always shown afterward. See ; below for syntax. ; ; Kbdinit is an optional routine called when Kermit starts up. It fills in ; the translation tables with desirable default values to save having to ; use long mskermit.ini files. The default values are stored in a structured ; table similar to (but not the same as) Dfkey's command lines; the keycode ; values are preset by hand to 16 bit numbers. ;Defining a key: ; Command is SET KEY ; ; is ; a single ordinary ascii char or ; the numerical equivalent of an ascii char or ; a Scan Code written as a number or ; keyword SCAN followed by a number. ; ? Displays help message. ; Numbers and Binary codes are of the form ; \123 a decimal number ; \o456 an octal number base letters o, d, x can be ; \d213 a decimal number upper or lower case ; \x0d a hex number ; \{b###} braces around above material following slash. ; ; is one or more spaces and or tabs. ; ; is ; missing altogether which "undefines" a key. ; \Kverb for a Kermit action verb; upper or lower case K is ok ; \{Kverb} ditto. Verb is the name of an action verb. ; text a string with allowed embedded whitespace and embedded ; binary chars as above. This kind of string may not ; commence with sequences \K or \{K; use braces below. ; {text} string confined to material within but excluding ; the braces. Note, where the number of opening braces ; exceeds the number of closing braces the end of line ; terminates the string: {ab{}{{c}d ==> ab{}{{c}d ; but {ab}{{c}d ==> ab. ; ? Displays help message and lists all action verbs. ; ; If Set Key is given interactively, as opposed to within a Take ; file, the system will prompt for inputs if none is on the command ; line. The response to Push key to be defined cannot be edited. ; ; Text which reduces to a single replacement character is put into a ; table separate from the multi-character strings (maxstng of these). ; A key may be translated into any single 8 bit code. ; ; Comments can follow a Kermit action verb or a braced string; no ; semicolon is required since all are stripped out by the Take file ; reader before the defining text is seen by SET KEY. ; ; The current Kermit escape character cannot be translated without ; subtrafuge. ; ; Examples: ; Set Key q z ; makes key q send character z ; Set Key \7 \27[0m ; makes key Control G send the four byte ; string ESC [ 0 m ; Set Key q ; undefines key q so it sends itself (q) again. ; Set Key \2349 \kexit ; defines IBM Alt-X to invoke the leave connect ; mode verb "exit" (Kermit's escape-char ^] C). ; Set Key \x0c Login \{x0d}myname\{x0d}mypass\x0d ; defines Control L to send the string ; Login mynamemypass ; ; Alternative Set Key syntax for backward compatibility with previous versions ; The same forms as above except the key identification number must ; be decimal and must Not have a leading backslash. Example: ; Set Key Scan 59 This is the F1 key ; ; If the definition is omitted it may be placed on the following line; ; if that line is also empty the key is undefined (defined as Self). ; A warning message about obsolete syntax will be given followed by ; the key's modern numerical value and new definition. Only "special" ; keys (those not producing ascii codes) are compatible with this ; translator. ; ;Showing a key: ; Command is SHOW KEY ; System prompts user to press a key and shows the definition plus the ; free space for strings. Query response results in showing all definitions. ; End Documentation code1 segment extrn vclick:near, udkclear:near ; in msyibm extrn xltkey:far ; in mszibm extrn iseof:far, strlen:far, prtscr:far ; in mssfil extrn domath:far, decout:far ; in msster assume cs:code1 fudkclear proc far call udkclear ret fudkclear endp fvclick proc far call vclick ret fvclick endp code1 ends code segment ; system independent external items extrn comnd:near, prompt:near, cnvlin:near ; in msscmd ; system dependent external items extrn beep:near, khold:near ; these are system dependent action verbs, in msxibm & msyibm extrn uparrw:near, dnarrw:near, rtarr:near, lfarr:near extrn pf1:near, pf2:near, pf3:near, pf4:near, kp0:near, kp1:near extrn kp2:near, kp3:near, kp4:near, kp5:near, kp6:near, kp7:near extrn kp8:near, kp9:near, kpminus:near, kpcoma:near, kpenter:near extrn kpdot:near, decf6:near, decf7:near, decf8:near, decf9:near extrn decf10:near, decf11:near, decf12:near, decf13:near extrn decf14:near, dechelp:near, decdo:near, decf17:near extrn decf18:near, decf19:near, decf20:near extrn decfind:near, decinsert:near, decremove:near extrn decselect:near, decprev:near, decnext:near, ignore_key:near extrn udkf6:near, udkf7:near, udkf8:near, udkf9:near, udkf10:near extrn udkf11:near,udkf12:near,udkf13:near,udkf14:near,udkf15:near extrn udkf16:near,udkf17:near,udkf18:near,udkf19:near,udkf20:near extrn chrout:near, cstatus:near, cquit:near, cquery:near extrn vtans52:near, vtinit:near, dnwpg:near, upwpg:near extrn endwnd:near, homwnd:near, upone:near, dnone:near, trnprs:near extrn trnmod:near, sendbr:near, sendbl:near, dmpscn:near, snull:near extrn chang:near, klogon:near, klogof:near, cdos:near extrn lfpage:near, rtpage:near, lfone:near, rtone:near, kdebug:near extrn extmacro:near extrn dgkc1:near,dgkc2:near,dgkc3:near,dgkc4:near,dgkf1:near extrn dgkf2:near,dgkf3:near,dgkf4:near,dgkf5:near,dgkf6:near extrn dgkf7:near,dgkf8:near,dgkf9:near,dgkf10:near,dgkf11:near extrn dgkf12:near,dgkf13:near,dgkf14:near,dgkf15:near extrn dgkSf1:near,dgkSf2:near,dgkSf3:near,dgkSf4:near,dgkSf5:near extrn dgkSf6:near,dgkSf7:near,dgkSf8:near,dgkSf9:near,dgkSf10:near extrn dgkSf11:near,dgkSf12:near,dgkSf13:near,dgkSf14:near extrn dgkSf15:near,dgpoint:near, dgnckey:near, kbdcompose:near extrn wykf1:near,wykf2:near,wykf3:near,wykf4:near,wykf5:near extrn wykf6:near,wykf7:near,wykf8:near,wykf9:near,wykf10:near extrn wykf11:near,wykf12:near,wykf13:near,wykf14:near,wykf15:near extrn wykf16:near extrn wykSf1:near,wykSf2:near,wykSf3:near,wykSf4:near,wykSf5:near extrn wykSf6:near,wykSf7:near,wykSf8:near,wykSf9:near,wykSf10:near extrn wykSf11:near,wykSf12:near,wykSf13:near,wykSf14:near extrn wykSf15:near, wykSf16:near extrn jpnxltkey:near ifndef no_network extrn ubhold:near ifndef no_tcp extrn nextses:near, tn_AYT:near, tn_IP:near extrn ses1:near,ses2:near,ses3:near,ses4:near,ses5:near,ses6:near endif ; no_tcp endif ; no_network assume cs:code, ds:data, es:data ; Begin system independent Keyboard Translator code ; MSUINIT performs Kermit startup initialization for this file. ; Note, shkadr and stkadr are pointers tested by Set/Show Key calls. If they ; are not initialized here then the older Set/Show Key procedures are called. MSUINIT PROC NEAR ; call from msx/msy init code call kbdinit ; optional: init translator tables mov shkadr,offset shkey ; declare keyboard translator present mov stkadr,offset dfkey ; via Show and Set Key proc addresses ret MSUINIT ENDP ; Call Keybd to read a keyboard char (just returns carry clear if none) and ; 1) send the replacement string (or original char if not translated) ; out the serial port, or ; 2) execute a Kermit action verb. ; Returns carry set if Connect mode is to be exited, else carry clear. ; Modifies registers ax and bx. KEYBD PROC NEAR ; active translator mov ttyact,1 ; doing single char output cmp stringcnt,0 ; any leftover string chars? je keybd0 ; e = no jmp keyst2 ; yes, finish string keybd0: call getkey ; read keyboard jnc keybd1 ; nc = data available jmp keybdx ; else just return carry clear keybd1: call postkey ; call system dependent post processor cmp nkeys,0 ; is number of keys defined = 0? jz keybd3 ; z = none defined push di ; search keylist for this keycode push cx ; save some registers push es mov di,offset keylist ; list of defined keycode words mov ax,keycode ; present keycode mov cx,nkeys ; number of words to examine push ds pop es ; make es:di point to data segment cld repne scasw ; find keycode in list pop es ; restore regs pop cx je keybd1b ; e = found, work with present di pop di ; restore original di test keycode,scan ; is this a scan code? jz keybd3 ; z = no, it's ascii, use al as char call beep ; say key is a dead one clc ret ; and exit with no action keybd1b:sub di,2 ; correct for auto increment sub di,offset keylist ; subtract start of list ==> listptr mov ax,dirlist[di] ; ax = contents of director word pop di ; restore original di ; dispatch on Director code test ax,verb ; verb only? jnz keyvb ; e = yes test ax,strng ; multi-char string only? jnz keyst ; e = yes, else single char & no xlat. ; ; do single CHAR output (char in al) keybd3: cmp termesc_flag,0 ; is escaping allowed? jne keybd3c ; ne = no, skip recognition cmp al,trans.escchr ; Kermit's escape char? je keybd3a ; e = yes, handle separately keybd3c:cmp isps55,0 ; [HF]940206 Japanese PS/55? je keybd3b ; [HF]940206 e = no call jpnxltkey ; [HF]940206 check Jpn.dble byte char jnc keybd3b ; [HF]940206 nc = no Jpn clc ; [HF]940206 return sccess ret ; [HF]940206 keybd3b:call xltkey ; do character set translation call chrout ; transmit the char clc ; return success ret keybd3a:stc ; set carry for jump to Quit ret keyvb: and ax,not(verb+strng) ; VERB (ax=index, remove type bits) mov bx,offset kverbs ; start of verb table cmp al,byte ptr [bx] ; index > number of entries? jae keybdx ; ae = illegal, indices start at 0 inc bx ; bx points to first entry push cx ; save reg mov cx,ax ; save the index in cx inc cx ; counter, indices start at 0 keyvb1: mov ax,[bx] ; cnt value add ax,4 ; skip text and value word add bx,ax ; look at next slot loop keyvb1 ; walk to correct slot sub bx,2 ; backup to value field pop cx ; restore reg mov bx,[bx] ; get value field of this slot or bx,bx ; jump address defined? jz keybdx ; z = no, skip the action jmp bx ; perform the function keyst: and ax,not(verb+strng) ; STRING (ax=index, remove type bits) shl ax,1 ; convert to word index push si ; save working reg mov si,ax ; word subscript in table mov si,sptable[si] ; memory offset of selected string xor cx,cx ; init string length to null or si,si ; is there a string pointer present? jz keyst1 ; z = no, skip operation cld ; scan forward mov cx,[si] ; get string length add si,2 keyst1: mov stringcnt,cx mov stringptr,si pop si jcxz keybdx ; z = null length keyst2: push si mov si,stringptr ; pointer to next string char cld lodsb ; get new string char into al pop si dec stringcnt ; string chars remaining inc stringptr call keysv ; scan for embedded verbs jc keyst4 ; c = not found, al has string char jmp bx ; perform the verb (bx = address) keyst4: call xltkey ; do character set translation cmp stringcnt,0 ; last character? je keyst5 ; e = yes, stop grouping for nets mov ttyact,0 ; group output for networks keyst5: jmp chrout ; send out the char in al keybdx: clc ; return success (nothing to do) ret KEYBD ENDP ; Scan for keyboard verbs embedded in outgoing string. If found update ; string pointer and count to just beyond the verb and return action routine ; address in bx with carry clear. If failure return carry set and no change. ; Can invoke external procedure EXTMACRO if the verb is not known here. keysv proc near push ax push si push di cmp al,'\' ; escape? jne keysv7 ; ne = no mov cx,stringcnt ; chars remaining mov si,stringptr ; address of next char to read mov brace,0 ; assume not using braces cmp byte ptr [si],braceop ; starts with \{? jne keysv1 ; ne = no inc si ; skip the opening brace dec cx mov brace,bracecl ; expect closing brace keysv1: cmp byte ptr [si],'K' ; starts with \{K or \K? je keysv2 ; e = yes cmp byte ptr [si],'k' ; starts as \{k or \k? jne keysv7 ; ne = no, then it's a string keysv2: inc si ; yes, skip the K too dec cx mov di,offset tranbuf ; copy verb name to this work buffer xor ax,ax mov [di],ax ; init the buffer to empty keysv3: cld jcxz keysv4 ; z = no more string chars lodsb ; scan til closing brace or w/s or end dec cx cmp al,brace ; closing brace? je keysv4 ; e = yes cmp al,'\' ; another item starting? jne keysv3a ; ne = no cmp brace,0 ; need to end on a brace? jne keysv4 ; ne = yes, backing up done below dec si ; back up to break position inc cx jmp short keysv4 ; process current substring keysv3a:cmp al,spc ; white space or control char? jbe keysv3 ; be = yes mov [di],ax ; copy to tranbuf and terminate inc di jmp short keysv3 keysv4: push si ; save input reading position mov si,offset tranbuf ; where verb starts (needs si) call tstkeyw ; find keyword, bx = action routine pop si jnc keysv4a ; nc = found the verb call keysv8 ; invoke EXTMACRO worker for unknown jc keysv7 ; carry = no verb to operate upon keysv4a:cmp brace,0 ; need to end on a brace? je keysv6 ; e = no dec si ; break position inc cx cld keysv5: jcxz keysv6 ; z = no more string characters lodsb ; read string char dec cx cmp al,brace ; the brace? jne keysv5 ; ne = no, repeat until it is found keysv6: mov stringptr,si ; where we finished+1 mov stringcnt,cx ; new count of remaining chars pop di pop si ; original si, starting place pop ax ; original ax clc ret keysv7: pop di ; verb not found pop si pop ax stc ret ; Worker. Unknown verb name as string {\kverb} or {\k{verb}}. Use EXTMACRO ; procedure (in msyibm typically), point to verb name with vtmacname, length ; of it in byte vtmaclen, address of EXTMACRO to BX. Upper case the verb. ; Enter with tranbuf holding the verb, asciiz, without \K and braces. ; Returns BX set to EXTMACRO proc, vtmacname pointing to verb (uppercased) ; and vtmaclen holding the length of verb. keysv8: mov bx,offset extmacro ; use this external macro pointer mov vtmacname,offset tranbuf; select extmacro procedure address mov dx,offset tranbuf ; point to name for extmacro push cx call strlen ; get its length mov vtmaclen,cx ; length for extmacro jcxz keysv11 ; z = none push si ; convert verb name to upper case mov si,dx ; verb, without leading \K stuff cld keysv9: lodsb ; read a name byte cmp al,'a' ; before lower case? jb keysv10 ; e = yes cmp al,'z' ; above lower case? ja keysv10 ; a = yes and al,not 20h ; convert to upper case mov [si-1],al ; put it back keysv10:loop keysv9 ; do all bytes, asciiz pop si pop cx clc ; carry clear = ready to execute ret keysv11:stc ; carry set = no verb, do nothing pop cx ret keysv endp ; SET KEY - define a key (procedure dfkey) ; SET KEY ; Call from Kermit level. Returns carry set if failure. ; DFKEY PROC NEAR ; define a key as a verb or a string mov keycode,0 ; clear keycode mov oldform,0 ; say no old form Set Key yet or byte ptr kbcodes,80h ; say kbcodes not-initiated mov bx,offset tranbuf ; our work space mov word ptr tranbuf,0 ; insert terminator mov dx,offset dfhelp1 ; first help message mov ah,cmword ; parse a word call comnd ; get key code or original ascii char jnc dfkey9 ret dfkey9: mov cl,taklev ; reading from Take file mov msutake,cl ; save here or ax,ax ; any text given? jnz dfkey12 ; nz = yes, so don't consider prompts ; interactive key request cmp taklev,0 ; in a Take file? je dfkey10 ; e = no, prompt for keystroke jmp dfkey0 ; else say bad syntax dfkey10:mov ah,prstr mov dx,offset dfaskky ; ask for key to be pressed int dos dfkey11:call getkey ; read key ident from keyboard jc dfkey11 ; c = no response, wait for keystroke mov ah,prstr ; display cr/lf mov dx,offset crlf int dos call shkey0 ; show current definition (in SHKEY) jmp dfkey1e ; prompt for and process definition dfkey12: ; Look for word SCAN and ignore it mov dx,word ptr tranbuf ; get first two characters or dx,2020h ; map upper to lower case cmp dx,'cs' ; first two letters of word "scan"? je dfkey ; e = yes, skip the word cmp dx,'lc' ; first two letters of word "clear"? je dfkey15 ; e = yes, reinit keyboard [2.31] cmp dx,'fo' ; first two letters of "off" je dfkey13 ; e = yes, use DOS keyboard calls cmp dx,'no' ; first two letters of "on" je dfkey13 ; e = yes, use standard kbd calls cmp dx,'kl' ; first two letters of "lk" (LK250)? je dfkey13 ; e = yes cmp ax,1 ; number of characters received jbe dfkey12a ; be = stay here jmp dfkey1 ; a = more than one, decode dfkey12a:mov ah,byte ptr tranbuf ; get the single char mov byte ptr keycode,ah ; store as ascii keycode jmp dfkey1b ; go get definition dfkey13:push dx ; save command letters mov ah,cmeol ; get end of line confirmation call comnd pop dx jnc dfkey14 ; nc = success ret dfkey14:mov al,0ffh ; set DOS keyboard read flag cmp dx,'fo' ; first two letters of "off" je dfkey14a ; e = yes, use DOS keyboard calls xor al,al ; clear DOS keyboard read flag cmp dx,'no' ; first two letters of "on" je dfkey14a ; e = yes, use standard kbd calls mov ah,dosflg ; get current flag mov dosflg,1 ; engage for chk250 test push ax call chk250 ; see if LK250 driver is present pop ax mov al,ah ; recover current setting cmp got250,0 ; did we find the driver? je dfkey14a ; e = no call kbrest ; and activiate it if so mov al,1 ; say LK250 dfkey14a:mov dosflg,al ; store new keyboard flag ret dfkey15:mov ah,cmeol call comnd ; confirm request before proceeding jnc dfkeyc ; nc = success ret ; failure dfkey0: push ds mov dx,seg dfhelp1 ; in seg data1 mov ds,dx mov dx,offset dfhelp1 ; say bad definition command mov ah,prstr int dos pop ds stc ; failure ret dfkeyc: ; CLEAR key defs, restore startup defs mov cx,maxkeys ; size of keycode tables push es ; save register push ds pop es ; make es point to data segment xor ax,ax ; null, value to be stored mov di,offset dirlist ; director table cld rep stosw ; clear it mov cx,maxkeys mov di,offset keylist ; keycode table rep stosw ; clear it mov cx,maxstng mov di,offset sptable ; string pointer table rep stosw ; clear it pop es ; recover register mov strmax,offset stbuf ; clear string buffer, free space ptr mov stbuf,0 ; first element of buffer mov nkeys,0 ; clear number of defined keys call msuinit ; restore startup definitions clc ; success ret ; Multi-char key identification dfkey1: mov si,offset tranbuf ; point to key ident text cmp byte ptr [si],'0' ; is first character numeric? jb dfkey1a ; b = no cmp byte ptr [si],'9' ; in numbers? ja dfkey1a ; a = no mov keycode,scan ; setup keycode for scan value mov dx,si ; get length of string in cx call strlen push ds pop es ; make es point to data segment push si add si,cx ; point at string terminator mov di,si inc di ; place to store string (1 byte later) inc cx ; include null terminator std ; work backward rep movsb ; move string one place later cld pop si mov byte ptr [si],'\' ; make ascii digits into \nnn form mov oldform,0ffh ; set old form flag mov dx,offset kwarnmsg ; tell user this is old form mov ah,prstr int dos dfkey1a:mov domath_ptr,si ; string push dx mov dx,si call strlen ; get its length pop dx mov domath_cnt,cx call domath ; convert numeric to binary in dx:ax jc dfkey0 ; c = no number converted or keycode,ax ; store in keycode dfkey1b: ; Get Definition proper test oldform,0ffh ; old form Set Key active? jz dfkey1f ; z = no mov bx,offset tranbuf ; get new definition on main cmd line mov dx,offset dfhelp2 ; help for definition of key mov comand.cmdonum,1 ; \number conversion allowed mov ah,cmline ; read rest of line into tranbuf call comnd ; allow null definitions mov cx,ax ; carry count in cx or ax,ax ; char count zero? jz dfkey1e ; z = zero, prompt for definition jmp dfkey2 ; process definition dfkey1e:mov ah,prstr mov dx,offset crlf int dos mov dx,offset dfaskdf ; prompt for definition string call prompt ; Kermit prompt routine mov comand.cmcr,1 ; permit bare carriage returns dfkey1f:mov bx,offset tranbuf ; get new definition mov dx,offset dfhelp2 ; help for definition of key mov comand.cmwhite,1 ; allow leading whitespace mov comand.cmdonum,1 ; \number conversion allowed mov comand.cmblen,length tranbuf mov ah,cmline ; read rest of line into tranbuf call comnd jc dfkey1x ; exit now on ^C from user mov cx,ax ; line count cmp comand.cmcr,0 ; prompting for definition? je dfkey1g ; e = no, trim leading whitespace mov comand.cmcr,0 ; turn off allowance for bare c/r's jmp dfkey2 ; interactive, allow leading whitespace dfkey1x:ret ; failure exit dfkey1g:push ax ; save count mov ah,cmeol ; get a confirm call comnd pop cx ; string length jc dfkey1x ; none so declare parse error dfkey2: ; Examine translation mov al,trans.escchr ; current escape char (port dependent) cmp al,byte ptr keycode ; is this Kermit's escape char? jne dfkey2a ; ne = no test keycode,scan ; see if scan code jnz dfkey2a ; nz = scan, so not ascii esc char mov dx,offset dfkoops ; Oops! msg mov ah,prstr ; complain and don't redefine int dos stc ; failure ret dfkey2a:push di ; get a director code for this key push cx mov di,offset keylist ; list of keycodes mov cx,nkeys ; number currently defined mov ax,keycode ; present keycode jcxz dfkey2b ; cx = 0 means none defined yet cld push ds pop es repne scasw ; is current keycode in the list? jne dfkey2b ; ne = not in list sub di,2 ; correct for auto increment sub di,offset keylist mov listptr,di ; list pointer for existing definition pop cx pop di jmp dfkey3 ; go process definition dfkey2b:pop cx ; key not currently defined so pop di ; make a new director entry for it mov bx,nkeys ; number of keys previously defined cmp bx,maxkeys ; enough space? jae dfkey2c ; ae = no, complain shl bx,1 ; count words mov listptr,bx ; index into word list mov ax,keycode ; get key's code mov keylist[bx],ax ; store it in list of keycodes mov dirlist[bx],0 ; clear the new director entry inc nkeys ; new number of keys jmp dfkey3 ; go process definition dfkey2c:mov dx,offset keyfull ; say key space is full already mov ah,prstr int dos stc ; failure ret ; listptr has element number in keylist or dirlist; keycode has key's code. ; Parse new definition. First look for Kermit verbs as a line beginning ; as \K or \{K. Otherwise, consider the line to be a string. ; In any case, update the Director table for the new definition. dfkey3: mov brace,0 ; assume not using braces mov si,offset tranbuf ; start of definition text cmp byte ptr [si],'\' ; starts with escape char? jne dfkey5 ; ne = no, so we have a string inc si ; skip the backslash cmp byte ptr [si],braceop ; starts with \{? jne dfkey3a ; ne = no inc si ; skip the opening brace mov brace,bracecl ; expect closing brace dfkey3a:cmp byte ptr [si],'K' ; starts with \{K or \K? je dfkey3b ; e = yes cmp byte ptr [si],'k' ; starts as \{k or \k? jne dfkey5 ; ne = no, then it's a string dfkey3b:inc si ; yes, skip the K too ; Kermit action VERBS push si ; save verb name start address dfkey4: cld lodsb ; scan til closing brace or w/s or end or al,al ; premature end? jz dfkey4b ; z = yes, accept without brace cmp al,braceop ; another opening brace? jne dfkey4a ; ne = no pop si ; clean stack jmp short dfkey5 ; it's a string dfkey4a:cmp al,'\' ; another object starting up? jne dfkey4d ; ne = no pop si ; clean stack jmp short dfkey5 ; it's a string dfkey4d:cmp al,brace ; closing brace? jne dfkey4 ; ne = no, not yet cmp byte ptr [si],0 ; closing brace terminates text? je dfkey4b ; e = yes, it's a verb pop si ; clean stack jmp short dfkey5 ; it's a string dfkey4b:pop si ; recover start address call tstkeyw ; find keyword, kw # returned in kbtemp jc dfkey5 ; c = not found, assume \kmacro. call remstr ; clear old string, if string mov ax,kbtemp ; save keyword number and ax,not(verb+strng) ; clear verb / string field or ax,verb ; set verb ident mov si,listptr mov dirlist[si],ax ; store info in Director table jmp dfkey7 ; show results and return success ; Here we are left with the definition string; si points to its start, and ; its length is in cx. Null length strings mean define key as Self, one ; byte means define as character, else as a string. ; STRING definitions dfkey5: push cx ; cx = length of definition string call remstr ; first, clear old string, if any pop cx mov si,offset tranbuf ; provide address of new string mov di,si call cnvlin ; convert numbers, cx gets line length mov si,offset tranbuf ; provide address of new string cmp cx,1 ; just zero or one byte to do? jbe dfkey6 ; e = yes, do as a char call insertst ; insert new string, returns reg cx. jc dfkey5h ; c = could not do insert mov si,listptr ; cx has type and string number mov dirlist[si],cx ; update Director table from insertst jmp dfkey7 ; show results and return success dfkey5h:mov dx,offset strbad ; display complaint mov ah,prstr int dos stc ; failure ret ; define SINGLE CHAR replacement or CLEAR a key definition. ; cx has char count 1 (normal) or 0 (to undefine the key). dfkey6: jcxz dfkey6c ; z = cx= 0, clear definition mov al,byte ptr [si] ; get first byte from definition xor ah,ah ; set the type bits to Char mov si,listptr mov dirlist[si],ax ; store type and key's new code jmp dfkey7 ; return success dfkey6c:push si ; clear a definition, push di ; listptr points to current def mov si,listptr ; starting address to clear add si,offset dirlist mov di,si ; destination add si,2 ; source is next word mov cx,nkeys ; current number of keys defined add cx,cx ; double for listptr being words sub cx,listptr ; cx = number of words to move shr cx,1 ; convert to actual number of moves jcxz dfkey6d ; z = none, just remove last word push es push ds pop es ; make es:di point to data segment cld push cx ; save cx rep movsw ; move down higher list items pop cx mov si,listptr ; do keylist too, same way add si,offset keylist mov di,si add si,2 rep movsw pop es dfkey6d:mov si,nkeys ; clear old highest list element shl si,1 ; address words mov dirlist[si],0 ; null the element mov keylist[si],0 ; null the element dec nkeys ; say one less key defined now pop di ; restore saved registers pop si dfkey7: mov ah,msutake ; Finish up. In a Take file? or ah,taklev ; or even directly or ah,ah jz dfkey7a ; z = no cmp flags.takflg,0 ; echo Take commands? je dfkey7b ; e = no dfkey7a:mov ah,prstr ; display cr/lf mov dx,offset crlf int dos call shkey0 ; show new definition (in SHKEY) call shkfre ; show free string space dfkey7b:clc ; return success ret DFKEY ENDP ; SHOW KEY command. Call from Kermit level. Vectored here by SHOW ; command. Replaces obsolete procedure in msx---. ; Prompts for a key and shows that key's (or all if ? entered) keycode, ; definition, and the key definition free space remaining. SHKEY PROC NEAR ; Show key's definition command mov ah,cmeol ; get a confirm call comnd ; ignore any additional text push bx mov dx,offset shkmsg1 ; ask for original key mov ah,prstr int dos or byte ptr kbcodes,80h ; say kbcodes not-initiated shky0: call getkey ; read keyboard, output to keycode jc shky0 ; wait for a key (c = nothing there) cmp byte ptr keycode,'?' ; query for all keys? jne shky0a ; ne = no, not a query test keycode,scan ; is this a scan code, vs ascii query? jz shky0c ; z = no Scan, so it is a query shky0a: mov ah,prstr ; show single key. Setup display mov dx,offset crlf int dos call shkey0 ; show just one key shky0b: call shkfre ; show free string space jmp shkeyx ; exit shky0c: mov cx,nkeys ; Show all keys. nkeys = number defined jcxz shky0b ; z = none to show mov si,offset keylist ; list of definitions push si ; save pointer shky1: pop si ; recover pointer cld lodsw ; get a keycode push si ; save pointer push cx ; save counter mov keycode,ax ; save new keycode mov ah,prstr mov dx,offset crlf int dos call shkey0 ; show this keycode pop cx ; pause between screens, recover cntr push cx ; save it again dec cx ; number yet to be shown jcxz shky1b ; z = have now shown all of them mov ax,nkeys ; number of defined keys sub ax,cx ; minus number yet to be displayed xor dx,dx ; clear extended numerator cmp isps55,0 ;[HF]940211 Japanese PS/55? je shky1d ;[HF]940211 e = no cmp ps55mod,0 ;[HF]940211 is system modeline active? jne shky1d ;[HF]940211 ne = no div eleven ;[HF]940211 yes, actvie screen is 23 jmp short shky1e ;[HF]940211 shky1d: div twelve ; two lines per definition display shky1e: or dx,dx ; remainder zero (12 defs shown)? jnz shky1b ; nz = no, not yet so keep going mov ah,prstr mov dx,offset shkmsg3 ; "push any key to continue" msg int dos shky1a: mov ah,0bh ; check console, check ^C int dos cmp flags.cxzflg,'C' ; a ^C? je shky1b ; e = yes, quit or al,al jz shky1a ; z = nothing call getkey ; get any key jc shky1a ; c = nothing at keyboard yet, wait shky1b: pop cx ; resume loop cmp flags.cxzflg,'C' ; a ^C? je shky1c ; e = yes, quit loop shky1 shky1c: pop si ; clean stack call shkfre ; show free string space jmp shkeyx ; exit ; show key worker routine, called from above ; SHKEY0 called by DFKEY just above SHKEY0: test keycode,scan ; scan code? jz shkey1 ; z = no, regular ascii ; SCAN codes mov dx,offset scanmsg ; say Scan Code: mov ah,prstr int dos mov ah,conout mov dl,'\' ; add backslash before number int dos mov ax,keycode ; get key's code again call decout ; display 16 bit decimal keycode jmp shkey2 ; go get definition shkey1: mov dx,offset ascmsg ; say ASCII CHAR mov ah,prstr int dos mov dl,byte ptr keycode ; get ascii code (al part of input) mov ah,conout cmp dl,spc ; control code? jae shkey1a ; ae = no push dx ; save char mov dl,5eh ; show caret first int dos pop dx add dl,'A'-1 ; ascii bias shkey1a:cmp dl,del ; DEL? jne shkey1b ; ne = no mov dl,'D' ; spell out DEL int dos mov dl,'E' int dos mov dl,'L' shkey1b:int dos mov dl,spc ; add a couple of spaces int dos int dos mov dl,'\' ; add backslash before number int dos mov ax,keycode ; show 16 bit keycode in decimal call decout ; and go get definiton ; Display defintion shkey2: mov dx,offset shkmsg2 ; intermediate part of reply mov ah,prstr ; " is defined as " int dos push di ; get a director code for this key push cx mov di,offset keylist ; list of keycodes mov cx,nkeys ; number currently defined jcxz shkey2a ; z = none mov ax,keycode ; present keycode push ds pop es ; use data segment for es:di cld repne scasw ; is current keycode in the list? jne shkey2a ; ne = not in list sub di,2 ; correct for auto increment sub di,offset keylist mov listptr,di ; list pointer for existing definition pop cx pop di jmp shkey3 ; go process definition shkey2a:pop cx pop di mov dx,offset noxmsg ; say Self (no translation) mov ah,prstr int dos ret ; return to main show key loop shkey3: ; translations, get kind of. mov si,listptr test dirlist[si],verb ; defined as verb? jnz shkey6 ; nz = yes, go do that one test dirlist[si],strng ; defined as string? jz shkey3a ; z = no jmp shkey8 ; yes, do string display shkey3a: mov dx,offset ascmsg ; CHAR. say 'Ascii char:' mov ah,prstr int dos mov ax,dirlist [si] ; get type and char mov dl,al ; put char here for display push ax ; save here too mov ah,conout cmp dl,spc ; control code? jae shkey4 ; ae = no push dx mov dl,5eh ; show caret int dos pop dx add dl,'A'-1 ; add ascii bias shkey4: cmp dl,del ; DEL? jne shkey4a ; ne = no mov dl,'D' ; spell out DEL int dos mov dl,'E' int dos mov dl,'L' shkey4a:int dos mov dl,spc ; add a couple of spaces mov ah,conout int dos int dos mov dl,'\' ; add backslash before number int dos pop ax ; recover char xor ah,ah ; clear high byte call decout ; show decimal value ret ; return to main show key loop shkey6: mov ah,prstr ; VERB mov dx,offset verbmsg ; say 'verb' int dos mov si,listptr ; get verb index from director mov dx,dirlist[si] and dx,not(verb+strng) ; remove type bits, leaves verb number mov bx,offset kverbs ; table of verbs & actions mov al,byte ptr [bx] ; number of keywords xor ah,ah dec ax mov kwcnt,ax ; save number of last one here cmp dx,ax ; asking for more than we have? ja shkeyx ; a = yes, exit bad inc bx ; point to first slot xor cx,cx ; current slot number shkey6b:cmp cx,dx ; this slot? je shkey6c ; e = yes, print the text part ja shkeyx ; a = beyond, exit bad mov ax,[bx] ; get cnt (keyword length) add ax,4 ; skip count and two byte value add bx,ax ; bx = start of next keyword slot inc cx ; current keyword number jmp short shkey6b ; try another shkey6c:push cx mov cx,[bx] ; length of definition add bx,2 ; look at text field mov di,bx ; offset for printing call prtscr ; print counted string mov ah,conout mov dl,spc ; add a couple of spaces int dos int dos mov dl,'\' ; show verb name as \Kverb int dos mov dl,'K' int dos call prtscr ; print counted string, again pop cx ret ; return to main show key loop shkey8: mov ah,prstr ; STRING mov dx,offset strngmsg ; say String: int dos mov si,listptr ; get index from director mov bx,dirlist[si] and bx,not(verb+strng) ; remove type bits shl bx,1 ; index words mov si,sptable[bx] ; table of string offsets mov cx,word ptr [si] ; get string length add si,2 ; point to string text mov ah,conout shkey8a:cld lodsb ; get a byte cmp al,127 ; DEL? je shkey8c ; e = yes cmp al,spc ; control code? jae shkey8b ; ae = no shkey8c:push ax mov dl,5eh ; show caret first int dos pop ax add al,40h ; convert to printable for display and al,7fh shkey8b:mov dl,al int dos ; display it loop shkey8a ; do another ret ; return to main show key loop shkeyx: pop bx ; restore reg clc ; return success ret SHKEY ENDP ;;; keyboard translator local support procedures, system independent ; Tstkeyw checks text word pointed to by si against table of keywords (pointed ; to by kverbs, made by mkeyw macro); returns in bx either action value or 0. ; Returns in kbtemp the number of the keyword and carry clear, or if failure ; returns kbtemp zero and carry set. ; Keyword structure is: dw cnt (length of string 'word') ; db 'word' (keyword string) ; dw value (value returned in bx) ; Make these with macro mkeyw such as mkeyw 'test',15 with the list of ; such keywords headed by a byte giving the number of keywords in the list. tstkeyw proc near push ax push cx push si mov verblen,0 ; verblen will hold verb length push si ; save user's verb pointer tstkw1: cld lodsb ; get a verb character cmp al,spc ; verbs are all non-spaces and above jbe tstkw2 ; be = done (space or control char) cmp word ptr [si-1],'}' ; closing brace? je tstkw2 ; e = yes, exclude as terminator inc verblen ; count verb length jmp short tstkw1 ; printable char, look for more tstkw2: pop si ; pointer to verb mov bx,offset kverbs ; table of Kermit verb keywords mov al,byte ptr [bx] ; number of keywords xor ah,ah mov kwcnt,ax ; save number of keywords here inc bx ; point bx to first slot mov kbtemp,0 ; remember which keyword tstkw3: ; match table keyword and text word mov cx,verblen ; length of user's verb cmp [bx],cx ; compare length vs table keyword jne tstkw4 ; ne = not equal lengths, try another push si ; lengths match, how about spelling? push bx add bx,2 ; point at start of keyword tstkw3a:mov ah,byte ptr [bx] ; keyword char mov al,byte ptr [si] ; text char cmp ah,'A' jb tstkw3b ; b = control chars cmp ah,'Z' ja tstkw3b ; a = not upper case alpha add ah,'a'-'A' ; convert upper case to lower case tstkw3b:cmp al,'A' jb tstkw3c cmp al,'Z' ja tstkw3c add al,'a'-'A' ; convert upper case to lower case tstkw3c:cmp al,ah ; test characters jne tstkw3d ; ne = no match inc si ; move to next char inc bx loop tstkw3a ; loop through entire length tstkw3d:pop bx pop si jcxz tstkw5 ; z: cx = 0, exit with match; ; else select next keyword tstkw4: inc kbtemp ; number of keyword to test next mov cx,kbtemp cmp cx,kwcnt ; all done? Recall kbtemp starts at 0 jae tstkwx ;ae = exhausted search, unsuccessfully mov ax,[bx] ; cnt (keyword length from macro) add ax,4 ; skip over count and two byte value add bx,ax ; bx = start of next keyword slot jmp tstkw3 ; do another comparison tstkw5: ; get action pointer mov ax,[bx] ; cnt (keyword length from macro) add ax,2 ; skip over count add bx,ax ; now bx points to dispatch value mov bx,[bx] ; bx holds dispatch value clc ; carry clear for success jmp short tstkwxx ; exit ret tstkwx: xor bx,bx ; exit when no match mov kbtemp,bx ; make verb number be zero too stc ; carry set for failure tstkwxx:pop si pop cx pop ax ret tstkeyw endp ; Insert asciiz string pointed to by si into string buffer stbuf. ; Reg cx has string length upon entry. ; Success: returns offset of first free byte (strmax) in string buffer stbuf, ; cx = type and Index of new string, and carry clear. ; Failure = carry set. insertst proc near push bx push dx push si push di push kbtemp ; save this variable too mov dx,cx ; save length of incoming string in dx mov bx,offset sptable ; table of string offsets mov kbtemp,0 ; slot number mov cx,maxstng ; number of entries, find an empty slot insert1:cmp word ptr[bx],0 ; slot empty? je insert2 ; e = yes inc kbtemp ; remember slot number add bx,2 ; look at next slot loop insert1 ; keep looking jmp short insert4 ; get here if no empty slots insert2: ; see if stbuf has sufficient space mov cx,dx ; length of new string to cx mov di,strmax ; offset of first free byte in stbuf add di,cx ; di = address where this string would end cmp di,offset stbuf+stbuflen ; beyond end of buffer? jae insert4 ; ae = yes, not enough room mov di,strmax ; point to first free slot in stbuf mov [bx],di ; fill slot with address offset of buffer push es push ds pop es ; point es:di to data segment cld mov [di],cx ; length of text for new string add di,2 ; move to next storage slot rep movsb ; copy string text pop es mov strmax,di ; offset of next free byte mov cx,kbtemp ; return new slot number with Director Index and cx,not(strng+verb) ; clear type bits or cx,strng ; say type is multi-char string clc ; say success jmp short insertx ; exit insert4:stc ; say no-can-do insertx:pop kbtemp pop di pop si pop dx pop bx ret insertst endp ; Remove (delete) string. Enter with listptr preset for director entry. ; Acts only on existing multi-char strings; recovers freed space. ; All registers preserved. remstr proc near push si mov si,listptr ; list pointer test dirlist[si],strng ; multi-char string? pop si jnz remst1 ; nz = a multi-char string ret ; else do nothing remst1: push ax push bx push cx push dx push si mov si,listptr mov ax,dirlist[si] ; Director table entry and ax,not(strng+verb) ; clear type bits, leave string's pointer mov dirlist[si],0 ; clear Director table entry shl ax,1 ; index words not bytes mov si,offset sptable ; list of string offsets in stbuf add si,ax ; plus index = current slot mov bx,[si] ; get offset of string to be deleted mov dx,bx ; save in dx for later mov cx,[bx] ; get length of subject string add cx,2 ; length word too, cx has whole length sub strmax,cx ; count space to be freed (adj end-of-buf ptr) mov word ptr [si],0 ; clear sptable of subject string address push cx ; save length of purged string push di ; save di push si push es ; save es push ds pop es ; setup es:di to be ds:offset of string mov di,dx ; destination = start address of purged string mov si,dx ; source = start address of purged string add si,cx ; plus string length of purged string. mov cx,offset stbuf+stbuflen ; 1 + address of buffer end sub cx,si ; 1 + number of bytes to move dec cx ; number of bytes to move jcxz remst2 ; z = none cld ; direction is forward rep movsb ; move down preserved strings remst2: pop es ; restore regs pop di pop si pop ax ; recover length of purged string (was in cx) mov bx,offset sptable ; string pointer table mov cx,maxstng ; max mumber of entries remst4: cmp [bx],dx ; does this entry occur before purged string? jbe remst5 ; be = before or equal, so leave it alone sub [bx],ax ; recompute address (remove old string space) remst5: add bx,2 ; look at next list entry loop remst4 ; do all entries in sptable pop si pop dx pop cx pop bx pop ax ret remstr endp shkfre proc near ; show free key & string defs & space push ax ; preserves all registers. push bx push cx push dx push kbtemp mov dx,offset fremsg mov ah,prstr int dos mov ax,maxkeys ; max number of key defs sub ax,nkeys ; number currently used call decout ; show the value mov ah,prstr mov dx,offset kyfrdef ; give key defs msg int dos mov bx,offset sptable ; table of string pointers mov cx,maxstng ; number of pointers mov kbtemp,0 ; number free shkfr1: cmp word ptr [bx],0 ; slot empty? jne shkfr2 ; ne = no inc kbtemp ; count free defs shkfr2: add bx,2 ; look at next slot loop shkfr1 ; do all of them mov ax,kbtemp ; number of free defs call decout ; display mov dx,offset stfrdef ; say free string defs mov ah,prstr int dos mov ax,offset stbuf+stbuflen ; 1 + last byte in stbuf sub ax,strmax ; offset of last free byte in stbuf call decout mov dx,offset stfrspc ; give free space part of msg mov ah,prstr int dos pop kbtemp pop dx pop cx pop bx pop ax ret shkfre endp ; Initialize the keyboard tables at Kermit startup time. Optional procedure. ; Requires kbdinlst to be configured with mkeyw macro in the form ; mkeyw 'definition',keytype*256+keycode ; keytype is 0 for scan codes and non-zero for ascii. ; Returns normally. kbdinit proc near ; read keyword kbdinlst and setup or byte ptr kbcodes,80h ; say kbcodes not-initiated push ds ; initial keyboard assignments. pop es ; set es:di to data segment inc taklev ; pretend that we are in Take file call chk250 ;** LK250 support begin cmp got250,1 ;** is it installed? jne kbdini0 ;** ne = no call kbrest ;** else initialize to DEC mode mov si,offset kb250lst ;** load extensions jmp short kbdini1 ;** LK250 support end kbdini0:mov si,offset kbdinlst ; start of list of definitions kbdini1:mov cx,[si] ; cnt field (keyword length of macro) jcxz kbdinix ; z = null cnt field = end of list add si,2 ; look at text field mov di,offset tranbuf ; where defkey expects text push cx cld rep movsb ; copy cx chars to tranbuf pop cx mov byte ptr [di],0 ; insert null terminator mov ax,word ptr [si] ; get value field mov keycode,ax ; set key ident value push si call dfkey2 ; put dfkey to work pop si add si,2 ; point to next entry jmp kbdini1 ; keep working kbdinix:dec taklev ; reset Take file level call fudkclear ; clear User Definable Keys mov cx,40h ; segment 40h mov es,cx mov cl,byte ptr es:[96h] ; kbd_flag_3, Enhanced keyboard area test cl,10h ; select Enhanced kbd presence bit jz kbdinx1 ; z = regular (88) mov keyboard,101 ; 101 = enhanced kbd kbdinx1:ret kbdinit endp ;;; End of System Independent Procedures ;;; Begin System Dependent Procedures ; Read keyboard. System dependent. ; Return carry set if nothing at keyboard. ; If char present return carry clear with key's code in Keycode. ; If key is ascii put that in the low byte of Keycode and clear bit Scan in ; the high byte; otherwise, put the scan code in the lower byte and set bit ; Scan in the high byte. ; Bit Scan is set if key is not an ascii code. ; Two methods are used: Bios reading for Set Key ON, and DOS reading for ; Set Key OFF. DOS scan codes are coerced to Bios values as much as possible. ; Modifies register ax. getkey proc near mov keycode,0 ; clear old keycode cmp dosflg,0ffh ; do DOS keyboard reading? je getky7 ; e = yes, DOS jmp getky6 ; do full Bios form ; ;;;;;;;; D O S ;;;;;;;;;; getky7: test byte ptr kbcodes,80h ; kbcodes initiated? [dan] jz getky5 ; z = yes [dan] and byte ptr kbcodes,not 80h ; say kbcodes initiated getky5: call iseof ; is stdin at eof? jnc getky5k ; nc = not eof, get more mov al,trans.escchr ; Kermit's escape char mov byte ptr keycode,al ; save ascii char clc ; to get out gracefully at EOF ret ; and exit getky5k:mov dl,0ffh ; DOS read operation mov ah,dconio ; from stdin int dos jnz getky5a ; nz = char available stc ; carry set = nothing available ret ; exit on no char getky5a:or al,al ; scan code precursor? jz getky5d ; z = yes cmp al,16 ; Control P? jne getky5b ; ne = no mov al,114 ; force Control PrtSc scan code jmp short getky5e ; process as scan code getky5b:cmp al,BS ; backspace key? jne getky5c ; ne = no mov al,14 ; force scan code for BS key jmp short getky5e ; process as scan code getky5c:mov byte ptr keycode,al ; save ascii char clc ; carry clear = got a char ret ; and exit getky5d:mov dl,0ffh ; read second byte (actual scan code) mov ah,dconio ; read via DOS int dos jnz getky5e ; nz = got a char stc ; none, declare bad read ret ; Check and modify to Bios scan codes getky5e:mov byte ptr keycode,al ; save char code cmp al,1 ; Alt escape je getkya ; set Alt bit cmp al,16 ; back tab jb getky5g ; these remain unchanged cmp al,50 ; start of meta keys jb getkya ; b = set Alt bit cmp al,84 ; Shift F1 jb getky5g ; b = no change cmp al,94 ; Control F1 jb getkys ; set Shift bit cmp al,104 ; Alt F1 jb getkyc ; set Control bit cmp al,114 ; Control PrtSc jb getkya ; set Alt bit cmp al,120 ; Alt top rank jb getkyc ; set Control bit cmp al,132 ; Control PgUp jb getkya ; set Alt bit je getkyc ; set Control bit cmp al,135 ; Shift F11, for Enhanced keyboard jb getky5g ; no change cmp al,137 ; Control F11 jb getkys ; set Shift bit cmp al,139 ; Alt F11 jb getky5c ; set Control bit cmp al,141 ; Control Up jb getkya ; set Alt bit cmp al,151 ; Alt Home jb getkyc ; set Control bit jmp short getkya ; set Alt bit getkyc: or keycode,control ; set Control bit jmp short getky5g getkys: or keycode,shift ; set Shift bit jmp short getky5g getkya: or keycode,alt ; set Alt bit getky5g:or keycode,scan ; ensure scan bit is set clc ; report we have a scan keycode ret ; and exit ; ;;;;;;;;;; B I O S ;;;;;;;;;;;;; getky6: ; full BIOS keyboard reading test byte ptr kbcodes,80h ; kbcodes initiated? [dan] jz getky6a ; z = yes [dan] mov kbcodes,0001h ; low byte = status, high = read char push cx ; save registers push es mov cx,40h ; segment 40h mov es,cx mov cl,byte ptr es:[96h] ; kbd_flag_3, Enhanced keyboard area and cl,10h ; select Enhanced kbd presence bit mov ch,cl ; copy, for both status and read or kbcodes,cx ; 0 = regular kbd, 10h = enhanced kbd pop es pop cx getky6a:mov ah,byte ptr kbcodes ; anything at keyboard? xor al,al int kbint ; Bios keyboard interrupt jnz getky1 ; nz = char available cmp ax,240 ; Bios "special ascii code" 0f0h? je getky1 ; e = yes, Bios makes error, is a key stc ; carry set = nothing available ret ; exit on no char available getky1: mov ah,byte ptr kbcodes+1 ; read, no echo, wait til done int kbint ; ==> ah = scan code, al = char value cmp ah,0 ; keycode entered by ALT ###? je getky1c ; e = yes, not enhanced cmp ah,0e0h ; Enhanced kbd Enter, fwd slash keys? jne getky1b ; ne = no xchg ah,al ; interchange scan and ascii fields getky1b:cmp al,0E0h ; enhanced key hidden code? jne getky1c ; ne = no mov byte ptr keycode,ah ; retain scan code, surpress 0e0h or keycode,scan+enhanced ; set scan and enhanced idents mov ah,2 ; use regular keyboard op code here int kbint ; get current shift state mov bl,al ; copy for a moment and bl,rgt_shift ; mask out all but right shift shl bl,1 ; move right shift to left shift pos or al,bl ; collapse shift bits and al,(lft_shift + alt_shift + ctl_shift) or byte ptr keycode+1,al ; store in type field of keycode clc ; say have a keystroke jmp getkyx ; Enhanced kbd end. Skip other tests getky1c:push cx mov cx,aliaslen ; number of aliased keys or cx,cx pop cx jz getky2 ; z = none push di ; check key (ax) for aliases push cx push es push ds pop es ; make es:di refer to data segment mov di,offset aliaskey ; list of aliased keys mov cx,aliaslen ; number of entries cld repne scasw ; look for a match pop es pop cx pop di jne getky2 ; ne = not there xor al,al ; force use of scan code (in ah) getky2: or al,al ; scan code being returned? jnz getky3 ; nz = no mov byte ptr keycode,ah ; store scan code for gsh push ax push bx call gsh ; get modified shift state or byte ptr keycode+1,al ; store in type field of keycode pop bx pop ax xchg ah,al ; put scan code in al or keycode,scan ; set scan flag (vs ascii) getky3: mov byte ptr keycode,al ; return key's code (usually ascii) clc ; carry clear = got a char getkyx: ret getkey endp ; get shift state into al. We care about only shift, ctl, and alt keys. ; right shift is collapsed into left shift. NumLock offsets Shift on keypad ; white keys. gsh proc near mov ah,2 int kbint ; get current shift state mov bl,al ; copy for a moment and bl,rgt_shift ; mask out all but right shift shl bl,1 ; move right shift to left shift pos or al,bl ; collapse shift bits cmp byte ptr keycode,71 ; below numeric key pad? jb gsh1 ; b = yes cmp byte ptr keycode,83 ; above numeric key pad? ja gsh1 ; a = yes cmp byte ptr keycode,74 ; grey - key ? je gsh1 ; e = yes cmp byte ptr keycode,78 ; grey + key je gsh1 ; e = yes test al,numlock ; numlock set? jz gsh1 ; z = no xor al,lft_shift ; numlock offsets shift and vice versa gsh1: and al,(lft_shift + alt_shift + ctl_shift) ret gsh endp ; Do any local processing after reading a key during active translation ; Avoids same actions if a key is being defined or shown. postkey proc near ; Key Click code for VT102 emulator cmp flags.vtflg,0 ; emulating? (0 = no) je postke1 ; e = extra clicks not available test vtemu.vtflgst,vskeyclick ; flags from SET TERM jz postke1 ; z = extra clicks not wanted call fvclick ; click, what else? postke1:ret postkey endp ;** start of LK250 stuff kbrest proc near ; set LK250 to DEC mode cmp got250,1 ; LK250 present? jne kbrest1 ; ne = no push es ; save reg mov ax,40h ; point to low memory mov es,ax or byte ptr es:[17h],20h ; ensure Num Lock is on and byte ptr es:[17h],0efh ; and Scroll is off pop es ; restore our [DS] mov ax,5001h ; issue set mode DEC to keyboard int 15h kbrest1:ret kbrest endp kbsusp proc near ; set LK250 to DOS mode cmp got250,1 ; LK250 present? jne kbsusp1 ; ne = no mov ax,5000h ; unload extensions int 15h kbsusp1:ret kbsusp endp kbhold proc near cmp got250,1 ; LK250 present? jne kbhold1 ; ne = no mov ax,5002h ; issue SET LEDS mov bl,0edh int 15h mov ax,5002h mov bl,holdscr ; get the hold state or bl,2 ; OR in Num Lock int 15h kbhold1:ret kbhold endp ;** end of LK250 stuff code ends code1 segment assume cs:code1 ; LK250 stuff chk250 proc far ; presence test for DEC LK250 keyboard mov got250,0 ; assume no LK250 keyboard cmp dosflg,1 ; use LK250? jne chk250x ; ne = no mov ax,sp ; do push sp test for XT vs AT/386 push sp ; XT pushes sp-2, AT's push old sp pop cx ; recover pushed value, clean stack xor ax,cx ; same? jne chk250a ; ne = no, XT. Don't do Int 15h mov ax,5000h ; see if the keyboard is loaded int 15h ; look for DOS->DEC mode driver cmp ax,1234h ; find marker 1234h jne chk250a ; ne = marker not present, no driver mov got250,1 ; else say we have an LK250 mov keyboard,250 ; global Variable chk250x:ret chk250a:mov ah,prstr mov dx,offset lk250msg ; say driver not active int dos ret chk250 endp code1 ends end