        page 62,132
; keyboard program for ibm pc
; from page 404 of May 1983 BYTE magazine;

keyadr  equ     (offset keybrd - offset start) + 100h
keylen  equ     offset keyend - offset keybrd
tabadr  equ     (offset table - offset keybrd) + 5Ch

tabddr  equ     (offset tabled - offset keybrd) + 5Ch
ctadr   equ     (offset ctable - offset keybrd) + 5Ch
oaltlc  equ     (offset altlc - offset keybrd) + 5Ch
oaltuc  equ     (offset altuc - offset keybrd) + 5Ch

kb_data equ     60h     ;keyboard data port
kb_ctl  equ     61h     ;keyboard control port

data    segment at 40h
        org     17h
kb_flag label   byte    ;ram keyboard flag byte

data    ends
cseg    segment
assume  cs:cseg,ds:data

        org     100h

start:  mov     dx, 5Ch     ;set ds:dx to loc 5ch in program prefix
        mov     al,9        ;set the keyboard interrupt (int9)
        mov     ah,25h      ; to ds:dx via DOS function call
        int     21h
        mov     di,dx   ;move keyboard routine down so it starts
        mov     si,keyadr       ; at loc 5ch in program prefix
        mov     cx,keylen       ; (saves space)
        jmp     finish

;keyboard interrupt routine.  copy beginning of IBM PC ROM routne to 
;allow easy jump to later ROM code

keybrd: push    ax      ;Save registers used
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    ds
        push    es
        cld
        mov     ax,data
        mov     ds,ax
        sti
        in      al,kb_data      ;get key code
        push    ax
        in      al,kb_ctl       ;restore keyboard
        mov     ah,al
        or      al,80h
        out     kb_ctl,al
        xchg    ah,al
        out     kb_ctl,al
        pop     ax
        mov     ah,al   ;save key code

;end of copied ROM code.  Start special translations

        cmp     al,0ffh ;overrun?
        jz      romkey
        mov     di,tabadr       ;translate key code
        cmp     cs:dvorak,28    ;use dvorak table?
        jnz     keybr0
        mov     di,tabddr       ;y
keybr0: and     al,7fh          ;kill make/break bit
        call    trans
        test    ah,80h          ;break code?
        jnz     romky0

        test    kb_flag,4       ;no. Ctrl key presse
        mov     di,ctadr
        jz      altran
        cmp     al,28           ;yep. enter key? (use dvorak?)
        jz      keybr2
keybr1: cmp     al,1            ;escape key?  (leave dvorak?)
        jnz     tran
keybr2: mov     cs:dvorak,al
        jmp     far ptr k26     ;restore regs and reti
                
altran: test    kb_flag,8       ;alt key pressed?
        jz      romkey
        mov     di,oaltlc
        test    kb_flag,43h     ;shift?
        jz      tran
        mov     di,oaltuc

tran:   call    trans
        jnz     romkey
        jmp     far ptr k61

romky0: or      al,80h
romkey: mov     ah,al
        jmp             far ptr romadr

;translate routine.  Replaces byte in string [di] by byte following
; matched byte.  Returns Z if no match found; NZ if match found.

trans:  cmp     al,cs:[di]
        jz      xfnd
        inc     di
        inc     di
        cmp     byte ptr cs:[di],0
        jnz     trans
        or      al,al
        ret                             ;RNZ
xfnd:   mov     al,cs:1[di]
        ret                             ;RZ


finish: rep     movsb
        mov     dx,di           ;end pgm but leave keyboard resident
        int     27h

dvorak  db      28       ;dvorak flag

table   db      43,42,74,43,0   ;backslash -> left shift, keypad- -> backslash

;for a Dvorak keyboard use

tabled  db   16,40,17,51,18,52,19,25,20,21,21,33,22,34,23,46,24,19,25,38,26,26
        db   30,30,31,24,32,18,33,22,34,23,35,32,36,35,37,20,38,49,39,31,40,53
        db   44,39,45,16,46,36,47,37,48,45,49,48,50,50,51,17,52,47,53,44,0

ctable  db      15,15,72,21     ;ctl_backtab-> ctl-O, ctl-uparrow->ctl-u
        db      80,10,0 ;ctl-downarrow->ctl-j

altlc   db      30,132,46,135,18,130,49,164,24,148,22,129,23,161,51,174,52,175
        db      02,173,53,168,03,253,13,240,32,235,0
altuc   db      30,142,46,128,18,138,49,165,24,153,22,154,02,173,53,168,05,156
        db      41,247,13,241,32,127,0

keyend:


cseg    ends

rom     segment         at 0f000h ;IBM ROM BIOS keyboard entry points
        assume  cs:rom
        org     0e9a6h
romadr  label   far             ;perform all bu initial processing

        org     0ea59h
k26     label   far             ;restore registers and return

        org     0ea7ch
k1234   label   far             ;reboot (ctl-alt-del addr)
        org     0ec05h
k61     label   far             ;store char in keyboard buffer and return
rom     ends

        end     start
