// KbdIOSubrs.bcpl // Last change July 23, 1983 9:45 PM by Bill van Melle // Major pruning December 14, 1982 2:55 PM by Bill van Melle // Last change July 21, 1982 9:51 PM by Bill van Melle // Wind change April 29, 1982 12:47 PM by Bill van Melle // Last change January 14, 1982 6:32 PM by Bill van Melle // Last change October 1, 1981 12:03 PM by Bill van Melle // Last change May 14, 1981 12:51 AM by Beau Sheil // Patched Tone change April 2, 1981 1:26 AM by Beau Sheil // Last change February 6, 1981 2:01 PM by Beau Sheil // Last change December 11, 1980 10:21 PM by Beau Sheil // Chord change November 19, 1980 8:48 PM by Beau Sheil get "AltoDefs.d" get "LispBcpl.decl" get "KbdDefs.d" get "Streams.d" get "SysDefs.d" external [ // SUBRS defined NWWInterrupt // other procedures defined KBDinit // statics defined keys // OS procedures used FindInterruptMask; InitializeInterrupt; CallSwat; Block Gets; Puts; Endofs; Resets; Max; Min; SetBlock; Zero; MoveBlock // other procs AllocVec; RAIDCode; FlashScreen // statics used OsBuffer; @lvNIL; @RMSK; ScreenWidth lispStarted; insideRaid ] static [ @KBDFlg = false @NewUS; @OldUS keys LockShift @DownStrokes; @UpStrokes ASCIImap @MEQLo; @MEQHi ScreenWidth= 1000 // to use for clipping until Init LispRegs ] manifest [ KBStackSize = 256 // stack depth for interrupts TrackMouse = true ] structure [ // function keys blank word 2 blank bit 4; CtrlBit bit; blank bit 4; LShiftBit bit; blank bit 6 blank byte; LockShiftBit bit; blank bit 3; RShiftBit bit; SwatBit bit; blank bit 2 ] // Normally init code like KBDinit would be in a separate file so its code // space could be reclaimed, but most of it is constants that have to be // around at run time anyway, so we dont bother. let KBDinit() be [ DownStrokes = table [ #177777; #177777; #173676; #177564; #377 ] UpStrokes = table [ #000000; #000000; #000000; #000000; #377 ] LockShift = table [ #013520; #036740; #013600; #175400; #000 ] ASCIImap = table [ // Unshifted characters, word 0 bs*S+lf; $\*S+$/; $p*S+$-; $k*S+$0; $v*S+$u; $d*S+$7; $e*S+$6; $4*S+$5; // word 1 spr1*S+spr2; $]*S+$'; $,*S+$l; $o*S+$x; $i*S+$9; $a*S+$s; $q*S+$w; $2*S+$3; // word 2 xxx*S+del; $←*S+rtn; $;*S+$.; lshft*S+$z; $b*S+$j; $c*S+ctrl; $f*S+tab; esc*S+$1; // word 3 xxx*S+xxx; spr3*S+rshft; $=*S+$[; space*S+lock; $m*S+$n; $8*S+$h; $y*S+$g; $t*S+$r // Buttons mb2*S+mb3; mb1*S+hs5; hs4*S+hs3; hs2*S+hs1; // Shifted characters, word 0 BS*S+LF; $|*S+$?; $P*S+$-; $K*S+$); $V*S+$U; $D*S+$&; $E*S+$~; $$*S+$%; // word 1 SPR1*S+SPR2; $}*S+$"; $<*S+$L; $O*S+$X; $I*S+$(; $A*S+$S; $Q*S+$W; $@*S+$#; // word 2 xxx*S+DEL; $↑*S+RTN; $:*S+$>; LSHFT*S+$Z; $B*S+$J; $C*S+CTRL; $F*S+TAB; ESC*S+$!; // word 3 xxx*S+xxx; SPR3*S+RSHFT; $+*S+${; SPACE*S+LOCK; $M*S+$N; $***S+$H; $Y*S+$G; $T*S+$R // buttons MB2*S+MB3; MB1*S+HS5; HS4*S+HS3; HS2*S+HS1; ] OldUS = AllocVec(USsize) // Fill in from Keys = #177034 MoveBlock(OldUS, Keys, USsize-1); OldUS!(USsize-1)=@buttons NewUS = AllocVec(USsize) // system keyboard buffer keys = AllocVec(lST); SetBlock(keys, CallSwat, lST) keys>>ST.par1 = OsBuffer keys>>ST.gets = kbdGets keys>>ST.puts = kbdPuts keys>>ST.endof = kbdEmpty keys>>ST.reset = kbdReset let WakeBit = FindInterruptMask(1 lshift (KeyboardLevel-1)) InitializeInterrupt(AllocVec(KBStackSize),KBStackSize,WakeBit,KBDHandler) @displayInterrupt = @displayInterrupt % WakeBit // arm the interrupt ] and KBDHandler() be [ // clip and track mouse compileif not TrackMouse then [ unless (insideRaid % not lispStarted) do return ] @mouseX = @mouseX le -16? -16, @mouseX gr ScreenWidth? ScreenWidth, @mouseX // let mouse get a cursor width's off left and top @cursorX = @mouseX @mouseY = @mouseY le -16? -16, @mouseY gr cursorYmax? cursorYmax, @mouseY @cursorY = @mouseY unless (insideRaid % not lispStarted) do return MoveBlock(NewUS, Keys, USsize-1) NewUS!(USsize-1)=@buttons for i = 0 to USsize-2 do [ let old = OldUS ! i let new = NewUS ! i let x = old & not new & DownStrokes!i if x ne 0 then KeyAction(x, i, DownStroke) // next two lines not needed as Upstroke[1-4]=0 // x = not old & new & UpStrokes!i // if x ne 0 then KeyAction(x, i, UpStroke) ] KBDFlg=OldUS; OldUS=NewUS; NewUS=KBDFlg // KBDFlg is used by NWWInterrupt to decide when a 60hz interrupt has // taken place. If so, NWWInterrupt will Block() and zero KBDFlg ] and KeyAction (b, w, action) be [ let shm = (NewUS>>LShiftBit eq 0? -1, NewUS>>RShiftBit eq 0? -1, NewUS>>LockShiftBit eq 0? LockShift!w, 0) let m, x = 1, w lshift 4 [ if (b&m) ne 0 then [ // "+ action" below only affects buttons let c = ASCIImap>>InputDatumMap.code↑((shm&m) eq 0? x, x+NoOfKeys) + action if (NewUS>>CtrlBit eq 0) & (c ge #100) then c = c & #237 unless Puts(keys, c) do FlashScreen() ] m, x = m lshift 1, x+1 ] repeatwhile m ne 0 ] and kbdGets(st) = valof // get with wait for input; for Raid [ let R=st>>ST.par1 while R>>OsBUF.Out eq R>>OsBUF.In do Block() // loop while st empty let x = @(R>>OsBUF.Out) let t = R>>OsBUF.Out + 1 if t eq R>>OsBUF.Last then t = R>>OsBUF.First R>>OsBUF.Out = t resultis x ] and kbdReset(st) be [ let buf = st>>ST.par1 let x = buf>>OsBUF.First buf>>OsBUF.In = x buf>>OsBUF.Out = x ] and kbdEmpty(st) = valof [ let R=st>>ST.par1 resultis R>>OsBUF.Out eq R>>OsBUF.In ] and kbdPuts(st, x) = valof [ let buf = st>>ST.par1 let t = buf>>OsBUF.In + 1 if t eq buf>>OsBUF.Last then t = buf>>OsBUF.First if t eq buf>>OsBUF.Out then resultis false //Overflow @(buf>>OsBUF.In) = x buf>>OsBUF.In = t resultis true ] and NWWInterrupt() = valof // Run whenever an interrupt occurs (>60hz). [ if (@(kbdAd+2) & #4102) eq 0 // CTRL-SHIFT-DEL then RAIDCode ("Ctrl-Shift-Del emergency interrupt", lvNIL) resultis lvNIL ]