; KeyStreamsA.asm -- Interrupt driven keyboard handler
; companion file is KeyStreamsB.bcpl
; Copyright Xerox Corporation 1979
; Last modified March 15, 1979 4:36 PM by Boggs
.titl KBHan
; outgoing
.ent kbInterrupt ; Interrupt routine
.bext CursorLink ; non zero => link the mouse to the cursor
.bext kbInterruptReMask
.bext kbUserProc
.bext kbUserProcStack
.bext kbTable
; incoming
.bext OsBuffer
StkMin = 335
.srel
kbInterrupt: .kbInterrupt
kbInterruptReMask: 0
CursorLink: -1 ; non zero => link mouse to cursor
kbUserProc: 0 ; address of user procedure
kbUserProcStack: 0 ; stack for same (non-zero => use proc)
kbTable: Transition
.nrel
mouseX: 424 ; address of mouse x coord
mouseY: 425 ; address of mouse y coord
cursorX: 426 ; address of cursor x coord
cursorY: 427 ; address of cursor y coord
XMax: 606.-16. ; maximum X value for mouse
YMax: 808.-16. ; maximum Y value for mouse
IMASK: kbInterruptReMask
.CursorLink: CursorLink
kbPC: 0 ; interrupted program's state
kbCry: 0
kbAC0: 0
kbAC1: 0
kbAC2: 0
kbAC3: 0
kbActive: 0
.Active: 453
.IntPC: 500
;----------------------------------------------------------------------------
.kbInterrupt: ; 16.666 ms vertical field interrupt
;----------------------------------------------------------------------------
sta 0 kbAC0
sta 1 kbAC1
sta 2 kbAC2
sta 3 kbAC3
movr 3 3
sta 3 kbCry
lda 0 @.IntPC
sta 0 kbPC ; save interrupt PC
lda 0 @.Active
lda 1 @IMASK ; save old active and mask out lower
and 0 1 ; priority interrupts while we run.
sta 1 @.Active
sta 0 kbActive
eir
; Update the cursor from the mouse unless CursorLink is 0.
lda 0 @.CursorLink
snz 0 0
jmp FL0 ; don't update coordinates
lda 0 @mouseX ; if mouseX < 0 then mouseX = 0
sp 0 0
mkzero 0 0
lda 1 XMax ; if mouseX > XMax then mouseX = XMax
subz# 0 1 snc
mov 1 0
sta 0 @cursorX ; store X coordinate for cursor
sta 0 @mouseX ; keep mouse incremental modulo screen limits
sta 0 userX
lda 0 @mouseY ; if mouseY < 0 then mouseY = 0
sp 0 0
mkzero 0 0
lda 1 YMax ; if mouseY > YMax then mouseY = YMax
subz# 0 1 snc
mov 1 0
sta 0 @cursorY ; store Y coordinate for cursor
sta 0 @mouseY ; keep mouse incremental modulo screen limits
sta 0 userY
; Now begin keyboard processing
FL0: jsr P ; locate ourselves
P: lda 2 CM5 ; count of times to go through loop
lop: lda 0 @Addrs+4-P,3 ; get keys bits
com 0 0 ; 1's imply keys down
lda 1 Masks+4-P,3 ; ignore some bits
and 1 0
lda 1 State+4-P,3 ; and current view of down keys
se 0 1 ; see if they differ
jmp dif ; yes
neg 3 3 ; move 3 down one
com 3 3
inc 2 2 szr ; go around loop 5 times
jmp lop
jmp NoTrans ; no differences
difadr: .blk 1
CM5: -5
; -------------------- K E Y B O A R D T A B L E --------------------------
; The format of kbTab through userY is published in SysDefs.d
kbTab: jsr 0,3 ; return address
Transition: .blk 1 ; transition index + #100000 if going down,
; or #40000 if coming up
State: .blk 5 ; 5 words of current keys state
userX: .blk 1 ; cursor coordinates
userY: .blk 1
Addrs: 177034 ; addresses of keyboard words
177035
kbdAd2: 177036
kbdAd3: 177037
177030 ; keyset and mouse.
Masks: 177777 ; 0 => ignore transition for this key
177777
177777
177777
377
downind: 100000
upind: 40000
Dismiss:dir
lda 0 kbPC
sta 0 @.IntPC
lda 0 kbActive
sta 0 @.Active
lda 0 kbAC0
lda 1 kbAC1
lda 2 kbAC2
lda 3 kbCry
movl 3 3
lda 3 kbAC3
bri
dif: sta 3 difadr ; remember where we found difference
com 2 2 ; neg and then sub 1 (now range 0 to 4)
addzl 2 2 ; multiply by 16
addzl 2 2
mov 0 3 ; 1 = old bits; 0 = new bits
andzl 1 3 ; xor function: 0 ← 1 xor 0
add 1 0
sub 3 0
subz 3 3 skp ; 0 has 1's where transitions
lop2: inc 2 2 ; bump bit index
movr 3 3 ; assemble a bit to match
movl 0 0 snc ; check for changed bit
jmp lop2 ; not found yet
; AC3 = bit that changed
; AC2 = index of bit that changed
; AC1 = old bits (still) 1's = down keys
lda 0 downind ; down indicator for transition
and# 3 1 szr ; check which way key went
sub 3 1 skp ; up - turn off bit
add 3 1 skp ; down - turn on bit
lda 0 upind ; up - up indicator
add 0 2 ; add indication to transition index
adc 0 0 ; for return test below
lda 3 difadr
sta 1 State+4-P,3 ; save new down bits
NoTrans: sta 2 Transition ; save transition indication
lda 2 @.UserProcStack
snz 2 2
jmp irecord ; no procedure -- I record it.
lda 0 StkMin ; save bottom of stack word
sta 0 StkMinSav
mkzero 0 0
sta 0 StkMin
jsr kbTab ; get table address
mov 3 0
lda 3 @.UserProc
jsr 0,3 ; go call him. ac0 => table
1
lda 1 StkMinSav
sta 1 StkMin
irecord:lda 1 Transition
movzl 1 1 szc ; if no down transition
snz 0 0 ; or if user returned false,
jmp Dismiss ; nothing more to do
jsr .+1
Q: movzr 1 1 ; get index back again (sans down bit)
add 1 3
; Get directive about what to do.
; Left byte has shift value; right unshifted value.
; Bit 0 is on if it's a letter.
lda 0 .kbTransitionTable-Q,3
snz 0 0
jmp Dismiss ; not a key OS cares about!
lda 1 @kbdAd3
lda 2 c200 ; <Lock>
and 1 2 szr
jmp Shift ; not locked -- check shift
movl# 0 0 szc ; send shifted character if it's a letter
jmp SendSh
Shift: lda 2 c10 ; <Right-Shift>
and 1 2 snr
jmp SendSh
lda 1 @kbdAd2
lda 2 c100 ; <Left-Shift>
and 1 2 snr
SendSh: movs 0 0 ; send character shifted
lda 3 c177
and 3 0
lda 1 @kbdAd2
lda 2 c4000 ; <Control>
lda 3 c37 ; control character (0-37B)
and 1 2 snr
and 3 0
sta 0 char ; save for a moment
lda 3 @.OsBuffer ; get pointer to buffer control
lda 2 2,3 ; "in" pointer
inc 2 1 ; 1 = newIn
lda 0 1,3 ; last
sne 1 0
lda 1 0,3 ; first
lda 0 3,3 ; out
sne 1 0
jmp Dismiss ; buffer full
lda 0 char
sta 0 0,2 ; store item
sta 1 2,3 ; new "in" pointer
jmp Dismiss
.OsBuffer: OsBuffer
.UserProc: kbUserProc
.UserProcStack: kbUserProcStack
StkMinSav: .blk 1
char: .blk 1
c4000: 4000 ; <Control>
c200: 200 ; <Lock>
c177: 177
c100: 100 ; <Left-Shift>
c37: 37
c10: 10 ; <Right-Shift>
;Tables for char code conversion
.ent kbTransitionTable
.srel
kbTransitionTable: .kbTransitionTable
.nrel
; structure KBKEY: // in SysDefs.d
; [
; Letter bit // True if char is a letter (use for lock interp)
; ShiftCode bit 7 // Code to use if shift is on
; NormCode bit 8 // Code to use otherwise
; ]
.kbTransitionTable:
45B7+65 ; % 5 177034
44B7+64 ; $ 4
176B7+66 ; ~ 6
1B0+105B7+145 ; E e
46B7+67 ; & 7
1B0+104B7+144 ; D d
1B0+125B7+165 ; U u
1B0+126B7+166 ; V v
51B7+60 ; ) 0
1B0+113B7+153 ; K k
30B7+55 ; ` -
1B0+120B7+160 ; P p
77B7+57 ; ? /
174B7+134 ; | \
140B7+12 ; ACCENT GRAVE LF
10B7+10 ; BS
43B7+63 ; # 3 177035
100B7+62 ; @ 2
1B0+127B7+167 ; W w
1B0+121B7+161 ; Q q
1B0+123B7+163 ; S s
1B0+101B7+141 ; A a
50B7+71 ; ( 9
1B0+111B7+151 ; I i
1B0+130B7+170 ; X x
1B0+117B7+157 ; O o
1B0+114B7+154 ; L l
74B7+54 ; < ,
42B7+47 ; " '
175B7+135 ; } ]
0 ; blank-middle or FR4
0 ; blank-top or BW
41B7+61 ; ! 1 177036
33B7+33 ; ESCAPE
11B7+11 ; TAB
1B0+106B7+146 ; F f
0 ; CONTROL
1B0+103B7+143 ; C c
1B0+112B7+152 ; J j
1B0+102B7+142 ; B b
1B0+132B7+172 ; Z z
0 ; SHIFT
76B7+56 ; > .
72B7+73 ; : ;
15B7+15 ; CR
136B7+137 ; ↑ ←
177B7+177 ; DEL (FL1)
0 ; FL3
1B0+122B7+162 ; R r 177037
1B0+124B7+164 ; T t
1B0+107B7+147 ; G g
1B0+131B7+171 ; Y y
1B0+110B7+150 ; H h
52B7+70 ; * 8
1B0+116B7+156 ; N n
1B0+115B7+155 ; M m
0 ; LOCK
40B7+40 ; SPACE
173B7+133 ; { [
53B7+75 ; +=
0 ; SHIFT
0 ; blank-bottom or FR1
0 ; FL4
0 ; FR5
.blk 16. ; zeroes for keyset keys
.END