home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
enterprs
/
c128
/
text
/
hacking6.arc
/
KEYSCAN.TXT
< prev
next >
Wrap
Text File
|
1993-09-16
|
31KB
|
728 lines
===============================================================================
THREE-KEY ROLLOVER for the C-128 and C-64.
by Craig Bruce <csbruce@neumann.uwaterloo.ca>
1. INTRODUCTION
This article examines a three-key rollover mechanism for the keyboards of the
C-128 and C-64 and presents Kernal-wedge implementations for both machines.
Webster's doesn't seem to know, so I'll tell you that this means that the
machine will act sensibly if you are holding down one key and then press
another without releasing the first (or even press a third key while holding
down two others). This is useful to fast touch typers. In fact, fast typing
without rollover can be quite annoying; you get a lot of missing letters.
Another annoying property of the kernel keyscanning is joystick interference.
If you move the joystick plugged into port #1, you will notice that some junk
keystrokes result. The keyscanners here eliminate this problem by simply
checking if the joystick is pressed and ignoring the keyboard if it is.
The reason that a 3-key rollover is implemented instead of the more general
N-key rollover is that scanning the keyboard becomes more and more unreliable
as more keys are held down. Key "shaddows" begin to appear to make it look
like you are holding down a certain key when you really are not. So, by
limiting the number of keys scanned to 3, some of this can be avoided. You
will get strange results if you hold down more than three keys at a time, and
even sometimes when holding down 3 or less. The "shift" keys (Shift,
Commodore, Control, Alternate, and CapsLock) don't count in the 3 keys of
rollover, but they do make the keyboard harder to read correctly.
Fortunately, three keys will allow you to type words like "AND" and "THE"
without releasing any keys.
2. USER GUIDE
Using these utilities is really easy - you just type away like normal. To
install the C-128 version, enter:
BOOT "KEYSCAN128"
and you're in business. The program will display "Keyscan128 installed" and
go to work. The program loads into memory at addresses $1500-$17BA (5376-6074
decimal), so you'll want to watch out for conflicts with other utilities.
This program also takes over the IRQ vector and the BASIC restart vector
($A00). The program will survive a RUN/STOP+RESTORE. To uninstall this
program, you must reset the machine (or poke the kernel values back into the
vectors); it does not uninstall itself.
Loading the C-64 version is a bit trickier, so a small BASIC loader program is
provided. LOAD and RUN the "KEYSCAN64.BOOT" program. It will load the
"KEYSCAN64" program into memory at addresses $C500-$C77E (50432-51070 decimal)
and execute it (with a SYS 50432). To uninstall the program, enter SYS 50435.
The program takes over the IRQ and NMI vectors and only gives them back to the
kernel upon uninstallation. The program will survive a RUN/STOP+RESTORE.
Something that you may or may not know about the C-64 is that its keys can be
made to repeat by poking to address 650 decimal. POKE650,128 will enable the
repeating of all keys. POKE650,0 will enable only the repeating of the SPACE,
DELETE, and CURSOR keys. POKE650,64 will disable the repeating of all keys.
An unusual side effect of changing this to either full repeat or no repeat is
that holding down SHIFT+COMMODORE (character set shift) will repeat rapidly.
To see the rollover in action, hold down the "J" key for a while, and then
press "K" without releasing "J". "K" will come out as expected, as it would
with the kernal. Now, release the "J" key. If you are on a C-128, you will
notice that the "K" key will now stop repeating (this is actually an important
feature - it avoids problems if you don't release all of the keys you are
holding down, at once). Now, press and hold the "J" key again without
releasing the "K". "J" will now appear. It wouldn't using the Kernal key
scanner. You can also try this with 3-key combinations. There will be some
combinations that cause problems; more on this below.
Also, take a spaz on the joystick plugged into port #1 and observe that no
garbage gets typed in. This was an annoying problem with the kernel of both
the 64 and 128 and has lead many different games to picking between joystick
#1 and #2 as the primary controller. The joystick in port #2 is not a problem
to either Keyscan-128/64 or the Kernal.
3. KEYBOARD SCANNING
The Kernal scans the keyboard sixty times a second to see what keys you are
holding down. Because of hardware peculiarities, there are multiple scanning
techniques that will give different results.
3.1. SCANNING EXAMPLE
An example program is included to demonstrate different keyboard scanning
techniques possible. To run it from a C-128 in 40-column (slow) mode, enter:
BOOT "KEYSHOW"
On a C-64, you must:
LOAD "KEYSHOW",8,1
and then:
SYS 4864
The same program works on both machines. Four maps of the keyscanning matrix
will be displayed on the 40-column screen, as scanned by different techniques.
The leftmost one is scanned from top to bottom "quickly". The second from the
left scans from bottom to top "quickly". The third from the left scans the
keyboard sideways, and the rightmost matrix scans the keys from top to bottom
"slowly".
The mapping of keyscan matrix positions to keys is as follows:
ROWS: \ COLUMNS: peek($DC01)
poke \
$DC00 \ 128 64 32 16 8 4 2 1
+-------+-------+-------+-------+-------+-------+-------+-------+
255-1 | DOWN | F5 | F3 | F1 | F7 | RIGHT | RETURN| DELETE|
+-------+-------+-------+-------+-------+-------+-------+-------+
255-2 |LEFT-SH| E | S | Z | 4 | A | W | 3 |
+-------+-------+-------+-------+-------+-------+-------+-------+
255-4 | X | T | F | C | 6 | D | R | 5 |
+-------+-------+-------+-------+-------+-------+-------+-------+
255-8 | V | U | H | B | 8 | G | Y | 7 |
+-------+-------+-------+-------+-------+-------+-------+-------+
255-16 | N | O | K | M | 0 | J | I | 9 |
+-------+-------+-------+-------+-------+-------+-------+-------+
255-32 | , | @ | : | . | - | L | P | + |
+-------+-------+-------+-------+-------+-------+-------+-------+
255-64 | / | ^ | = |RGHT-SH| HOME | ; | * | \ |
+-------+-------+-------+-------+-------+-------+-------+-------+
255-128 | STOP | Q |COMMODR| SPACE | 2 |CONTROL| _ | 1 |
+-------+-------+-------+-------+-------+-------+-------+-------+
The following table contains the additional keys which must be scanned on the
C128 (but which are not displayed by the example scanning program).
ROWS: \ COLUMNS: peek($DC01)
poke \
$D02F \ 128 64 32 16 8 4 2 1
+-------+-------+-------+-------+-------+-------+-------+-------+
255-1 | 1 | 7 | 4 | 2 | TAB | 5 | 8 | HELP |
+-------+-------+-------+-------+-------+-------+-------+-------+
255-2 | 3 | 9 | 6 | ENTER | LF | - | + | ESC |
+-------+-------+-------+-------+-------+-------+-------+-------+
255-4 |NO-SCRL| RIGHT | LEFT | DOWN | UP | . | 0 | ALT |
+-------+-------+-------+-------+-------+-------+-------+-------+
These tables are presented on page 642 of the Commodore 128 Programmer's
Reference Guide. The scan codes that are stored in location 212 on the C128
and location 197 on the C64 are calculated based on the above tables. The
entry in the "1" bit position of the first line of the first table (DELETE)
has a scan code of 0, the "2" entry (RETURN) has a scan code of 1, etc., the
entry on the second scan line in the "1" position ("3") has a scan code of 8,
etc., all the way down to code 63. The scan codes for the 128 go all the way
to 87, continuing in the second table like the first.
You will notice some strange effects of the different scanning techniques when
you hold down multiple keys. More on this below. Also try pushing joystick
#1 around.
3.2. SCANNING HARDWARE
To scan the 128 keyboard, you must poke a value into $DC00 (CIA#1 port A) and
$D02F (VIC chip keyboard select port) to select the row to be scanned. The
Data Direction Register for this port will be set to all outputs by the
Kernal, so you don't have to worry about it. Each bit of $DC00 and the three
least significant bits of $D02F are used for selecting rows. A "0" bit means
that a row IS selected, and a "1" means that a row IS NOT selected. The poke
value to use for selecting among the various rows are given in the two tables
in the previous section.
Using one bit per row allows you to select multiple rows at the same time. It
can be useful to select all rows at one time or no rows. To read the row that
has been selected, simply peek at location $DC01 (CIA#1 port B). Each bit
will tell you whether the corresponding key is currently being held down or
not. Again, we have reverse logic; a "0" means that the key is being held
down, and a "1" means that the key is not held down. The bit values
corresponding to the keys are given as the column headings in the tables in
the previous section. Since there is no such thing as a perfect mechanical
switch, it is recommended that you "debounce" each key row read in the
following way:
again:
lda $dc01
cmp $dc01
bne again
So, to scan the entire keyboard, you simply select each scan row in some
order, and read and remember the keys held down on the row. As it turns out,
you have to be a bit careful of exactly how you "select" a row. Also, there
is a shortcut that you can take. In order to find out if any key is being
held down in one operation, all you have to do is select all rows at once and
see if there are any "0" bits in the read value. If so, there is a key being
held down somewhere; if not, then there is no key being held down, so you
don't have to bother scanning the entire keyboard. This will reduce our
keyscanning significantly, which is important, since the keyboard will be
scanned every 1/60 of a second.
As mentioned above, joystick #1 will interfere with the Kernal reading the
keyboard. This is because the read value of joystick #1 is wired into CIA#1
port A, the same place that the keyboard read is wired in. So, whenever a
switch in the joystick is pushed, the corresponding bit of the keyboard scan
register will be forced to "0", regardless of which keys are pressed and
regardless of which scan row is selected. There's the catch. If we were to
un-select all scan rows and still notice "0"s in the keyboard read register,
then we would know that the joystick was being pushed and would interfere with
our keyboard scanning, so we could abort keyboard scanning and handle this
case as if no keys were being held down.
It still would be possible but unlikely that the user could push the joystick
in the middle of us scanning the keyboard and screw up our results, so to
defend against this, we check for the joystick being pushed both before and
after scanning the keyboard. If we find that the joystick is pushed at either
of these times, then we throw out the results and assume that no keys are held
down. This way, the only way that a user could screw up the scanning is if
he/she/it were to press a switch after we begin scanning and release it before
we finish scanning. Not bloody likely for a human.
You get the same deal for keyboard scanning on the 64, except you only need to
use $DC00 for selecting the scan rows. Also note that you will not be able to
play with keyboard scanning from BASIC because of the interrupt reading of the
keyboard. You must make sure that interrupts are disabled when playing with
the keyboard hardware, or interrupt scanning can come along at any time and
change all of the register settings.
3.3. SCANNING SOURCE CODE
The four keyboard scanning techniques of the example program are presented
below. The declarations required for all of them are:
pa = $dc00 ;row select
pb = $dc01 ;column read
ddra = $dc02 ;ddr for row select
ddrb = $dc03 ;ddr for column read
scanTable .buf 8 ;storage for scan
mask = $03 ;work location
The code is as follows, in Buddy format. Each routine scans the keyboard and
stores the results in the "scanTable" table.
------------------+------------------+------------------+------------------+
Row forward fast | Row backward fast| Column right | Row forward slow
------------------+------------------+------------------+------------------+
sei | sei | sei | sei
ldx #0 | ldx #7 | lda #$00 | ldx #0
lda #$fe | lda #$7f | sta ddra | lda #$fe
sta pa | sta pa | lda #$ff | sta mask
nextRow = * | nextRow = * | sta ddrb | nextRow = *
- lda pb |- lda pb | ldy #7 | lda mask
cmp pb | cmp pb | lda #$7f | sta pa
bne - | bne - | sta mask |- lda pb
eor #$ff | eor #$ff | nextCol = * | cmp pb
sta scanTable,x | sta scanTable,x | lda mask | bne -
sec | sec | sta pb | eor #$ff
rol pa | ror pa |- lda pa | sta scanTable,x
inx | dex | cmp pa | sec
cpx #8 | bpl nextRow | bne - | rol mask
bcc nextRow | cli | ldx #$ff | inx
cli | rts | stx pb | cpx #8
rts | | eor #$ff | bcc nextRow
------------------+------------------+ ldx #7 | cli
|- asl | rts
The forward "quick" scanning stores | rol scanTable,x +------------------+
the scan row selection mask into | dex |
the row selection register and | bpl - |
shifts the "0" bit one position | sec |
"forward" for each row, directly, | ror mask |
using a "rol $dc00" instruction. | dey |
This would probably be the obvious | bpl nextCol |
solution to an optimizing assembler | lda #$ff |
programmer. However, for some | sta ddra |
reason not quite understood by this | lda #$00 |
author, there are "shadowing" | sta ddrb |
problems with this approach. If | cli |
you were to hold down the two keys | rts |
"H" and "K" at the same time, you +------------------+
would notice that these two keys
are on the same column of two successive rows. If you hold them both down,
you will see the two positions become active, but so will the same column of
all successive rows after the "H" and "K", even though these other keys are
not actually held down. You will get an inaccurate reading if bad keys are
held down simultaneously. You will notice the use of the term "active" above.
This is because although the hardware returns a "0" for active, the routine
converts that into a "1" for easier processing later. I am not sure if
everyone will get this same result, but if your keyboard is wired the same as
mine, you will.
The backward "quick" scanning operates quite similarly to the forward
scanning, except for the direction of the scan and the direction of the
"shadow"; the shadow goes upwards. You might think that ANDing together the
results of the forward and backward scan together would eliminate the shadow,
but this will not work since any rows between the rows containing the two keys
held down will be incorrectly read as being active.
The columnwise right scanning is the most complicated because the rows must be
converted into columns, to allow the scan matrix to be interpreted as before.
Also, the Data Direction Registers have to be changed. You might think that
combinging row-wise scanning with columnwise scanning would give better
results, and it probably would, if it weren't for a bizarre hardware problem.
If you hold down two or more keys on the same scan row, say "W" and "E", some
of the keys will flicker or disappear, giving an inaccurate reading.
The forward "slow" scanning is the best of the bunch. Incidentally, it is
what the Kernal uses (as near as I can figure - their code is extremely
convoluted). This technique is the same as the forward "quick scan," except
that the row selection mask is shifted in a working storage location and poked
into the CIA register, rather than being shifted in place. I don't know why
this makes a difference, but it does. There is still a problem with this
technique, but this problem occurs with all techniques. If you hold down
three keys that form three "corners" of a rectangle in the scanning matrix,
then the missing corner will be read as being held down also. For example, if
you hold down "C", "N", and "M", then the keyboard hardware will also think
that you are holding down the "X" key. This is why this article implements a
"three-key" rollover rather than an "N-key" rollover. Many three-key
combinations will still be interpreted correctly. Note, however, that shift
keys such as SHIFT or CONTROL will add one more key to the hardware scanning
(but will not be counted in the three-key rollover), making inaccurate results
more likely if you are holding down multiple other keys at the same time.
4. THE C-128 KEYSCANNER
This section gives the source code for the C-128 implementation of the
three-key rollover. The forward "slow" key matrix scanning technique is used,
extended to work with the extra keys of the 128. It was a bit of a pain
wedging into the Kernal, since there is not a convenient indirect JMP into
scanning the keyboard, like there are for decoding and buffering pressed keys.
A rather lengthy IRQ "preamble" had to be copied from the ROM, up to the
point where it JSRs to the keyscanning routine. This code in included in
the form of a ".byte" table, to spare you the details.
Before scanning the keyboard, we check to see if joystick #1 is pushed and if
a key is actually pressed. If not, we abort scanning and JMP to the key
repeat handling in the ROM. If a key is held down, we scan the keyboard and
then examine the result. First we check for the shift keys (SHIFT, COMMODORE,
CONTROL, ALT, and CAPS LOCK), put them into location $D3 (shift flags) in bit
postitions 1, 2, 4, 8, and 16, respectively, and remove them from the scan
matrix. The CAPS LOCK key is not on the main key matrix; it is read from the
processor I/O port. This is good, because otherwise we could not abort
scanning if it were the only key held down.
Then we scan the keymatrix for the first three keys that are being held down,
or as many as are held down if less than three. We store the scan codes of
these keys into a 3-element array. We also retain a copy of the 3-element
array from the previous scan and we check for different keys being in the two
arrays. If the old array contains a key that is not present in the new array,
then the use has released a key, so we set a flag to inhibit interpretation of
keys and pretend that no keys are held down. This is to eliminate undesirable
effects of having other keys held down repeat if you release the most recently
pushed key first. PC keyboards do this. This inhibiting will be ignored if
new keys are discovered in the next step.
If there are keys in the new array that are not in the old, then the user has
just pressed a new key, so that new key goes to the head of the old array and
we stop comparing the arrays there. The key in the first position of the old
array is poked into the Kernal "key held down" location for the Kernal to
interpret later. If more than one new key is discovered at the same time,
then each of the new keys will be picked up on successive keyboard scans and
will be interpreted as just being pushed. So, if you press the "A", "N", and
"D" keys all at the same time, some permutation of all three of these keys
will appear on the screen.
When we are done interpreting the keys, we check the joystick once more and if
it is still inactive, we present the most recently pushed down key to the
Kernal and JMP into the ROM keyboard decoding routine.
Unlike in previous issues, this source code is here in literal form; just
extract everything between the "-----=-----"s to nab the source for yourself.
The source is in Buddy assembler format.
-----=-----
;3-Key Rollover-128 by Craig Bruce 18-Jun-93 for C= Hacking magazine
.org $1500
.obj "@0:keyscan128"
scanrows = 11
rollover = 3
pa = $dc00
pb = $dc01
pk = $d02f
jmp initialInstall
;ugly IRQ patch code.
irq = * ;$1503
.byte $d8,$20,$0a,$15,$4c,$69,$fa,$38,$ad,$19,$d0,$29,$01,$f0,$07,$8d
.byte $19,$d0,$a5,$d8,$c9,$ff,$f0,$6f,$2c,$11,$d0,$30,$04,$29,$40,$d0
.byte $31,$38,$a5,$d8,$f0,$2c,$24,$d8,$50,$06,$ad,$34,$0a,$8d,$12,$d0
.byte $a5,$01,$29,$fd,$09,$04,$48,$ad,$2d,$0a,$48,$ad,$11,$d0,$29,$7f
.byte $09,$20,$a8,$ad,$16,$d0,$24,$d8,$30,$03,$29,$ef,$2c,$09,$10,$aa
.byte $d0,$28,$a9,$ff,$8d,$12,$d0,$a5,$01,$09,$02,$29,$fb,$05,$d9,$48
.byte $ad,$2c,$0a,$48,$ad,$11,$d0,$29,$5f,$a8,$ad,$16,$d0,$29,$ef,$aa
.byte $b0,$08,$a2,$07,$ca,$d0,$fd,$ea,$ea,$aa,$68,$8d,$18,$d0,$68,$85
.byte $01,$8c,$11,$d0,$8e,$16,$d0,$b0,$13,$ad,$30,$d0,$29,$01,$f0,$0c
.byte $a5,$d8,$29,$40,$f0,$06,$ad,$11,$d0,$10,$01,$38,$58,$90,$07,$20
.byte $aa,$15,$20,$e7,$c6,$38,$60
;keyscanning entry point
main = *
lda #0 ;check if any keys are held down
sta pa
sta pk
- lda pb
cmp pb
bne -
cmp #$ff
beq noKeyPressed ;if not, then don't scan keyboard, goto Kernal
jsr checkJoystick ;if so, make sure joystick not pressed
bcc joystickPressed
jsr keyscan ;scan the keyboard and store results
jsr checkJoystick ;make sure joystick not pressed again
bcc joystickPressed
jsr shiftdecode ;decode the shift keys
jsr keydecode ;decode the first 3 regular keys held down
jsr keyorder ;see which new keys pressed, old keys released, and
; determine which key to present to the Kernal
lda $033e ;set up for and dispatch to Kernal
sta $cc
lda $033f
sta $cd
ldx #$ff
bit ignoreKeys
bmi ++
lda prevKeys+0
cmp #$ff
bne +
lda $d3
beq ++
lda #88
+ sta $d4
tay
jmp ($033a)
noKeyPressed = * ;no keys pressed; select default scan row
lda #$7f
sta pa
lda #$ff
sta pk
joystickPressed = *
lda #$ff ;record that no keys are down in old 3-key array
ldx #rollover-1
- sta prevKeys,x
dex
bpl -
jsr scanCaps ;scan the CAPS LOCK key
ldx #$ff
lda #0
sta ignoreKeys
+ lda #88 ;present "no key held" to Kernal
sta $d4
tay
jmp $c697
initialInstall = * ;install wedge: set restore vector, print message
jsr install
lda #<reinstall
ldy #>reinstall
sta $0a00
sty $0a01
ldx #0
- lda installMsg,x
beq +
jsr $ffd2
inx
bne -
+ rts
installMsg = *
.byte 13
.asc "keyscan128 installed"
.byte 0
reinstall = * ;re-install wedge after a RUN/STOP+RESTORE
jsr install
jmp $4003
install = * ;guts of installation: set IRQ vector to patch code
sei ; and initialize scanning variables
lda #<irq
ldy #>irq
sta $0314
sty $0315
cli
ldx #rollover-1
lda #$ff
- sta prevKeys,x
dex
bpl -
lda #0
sta ignoreKeys
rts
mask = $cc
keyscan = * ;scan the (extended) keyboard using the forward
ldx #$ff ; row-wise "slow" technique
ldy #$ff
lda #$fe
sta mask+0
lda #$ff
sta mask+1
jmp +
nextRow = *
- lda pb
cmp pb
bne -
sty pa
sty pk
eor #$ff
sta scanTable,x
sec
rol mask+0
rol mask+1
+ lda mask+0
sta pa
lda mask+1
sta pk
inx
cpx #scanrows
bcc nextRow
rts
shiftValue = $d3
shiftRows .byte $01,$06,$07,$07,$0a
shiftBits .byte $80,$10,$20,$04,$01
shiftMask .byte $01,$01,$02,$04,$08
shiftdecode = * ;see which "shift" keys are held down, put them into
jsr scanCaps ; proper positions in $D3 (shift flags), and remove
ldy #4 ; them from the scan matrix
- ldx shiftRows,y
lda scanTable,x
and shiftBits,y
beq +
lda shiftMask,y
ora shiftValue
sta shiftValue
lda shiftBits,y
eor #$ff
and scanTable,x
sta scanTable,x
+ dey
bpl -
rts
scanCaps = * ;scan the CAPS LOCK key from the processor I/O port
- lda $1
cmp $1
bne -
eor #$ff
and #$40
lsr
lsr
sta shiftValue
rts
newpos = $cc
keycode = $d4
xsave = $cd
keydecode = * ;get the scan codes of the first three keys held down
ldx #rollover-1 ;initialize: $ff means no key held
lda #$ff
- sta newKeys,x
dex
bpl -
ldy #0
sty newpos
ldx #0
stx keycode
decodeNextRow = * ;decode a row, incrementing the current scan code
lda scanTable,x
beq decodeContinue
;at this point, we know that the row has a key held
ldy keycode
- lsr
bcc ++
pha ;here we know which key it is, so store its scan code,
stx xsave ; up to 3 keys
ldx newpos
cpx #rollover
bcs +
tya
sta newKeys,x
inc newpos
+ ldx xsave
pla
+ iny
cmp #$00
bne -
decodeContinue = *
clc
lda keycode
adc #8
sta keycode
inx
cpx #scanrows
bcc decodeNextRow
rts
;keyorder: determine what key to present to the Kernal as being logically the
;only one pressed, based on which keys previously held have been released and
;which new keys have just been pressed
keyorder = *
;** remove old keys no longer held from old scan code array
ldy #0
nextRemove = *
lda prevKeys,y ;get current old key
cmp #$ff
beq ++
ldx #rollover-1 ;search for it in the new scan code array
- cmp newKeys,x
beq +
dex
bpl -
tya ;here, old key no longer held; remove it
tax
- lda prevKeys+1,x
sta prevKeys+0,x
inx
cpx #rollover-1
bcc -
lda #$ff
sta prevKeys+rollover-1
sta ignoreKeys
+ iny ;check next old key
cpy #rollover
bcc nextRemove
;** insert new keys at front of old scan code array
+ ldy #0
nextInsert = *
lda newKeys,y ;get current new key
cmp #$ff
beq ++
ldx #rollover-1 ;check old scan code array for it
- cmp prevKeys,x
beq +
dex
bpl -
pha ;it's not there, so insert new key at front, exit
ldx #rollover-2
- lda prevKeys+0,x
sta prevKeys+1,x
dex
bpl -
lda #0
sta ignoreKeys
pla
sta prevKeys+0
ldy #rollover ;(trick to exit)
+ iny
cpy #rollover
bcc nextInsert
+ rts ;now, the head of the old scan code array contains
; the scan code to present to the Kernal, and other
; positions represent keys that are also held down
; that have already been processed and therefore can
; be ignored until they are released
checkJoystick = * ;check if joystick is pushed: un-select all keyboard
lda #$ff ; rows and see if there are any "0"s in the scan
sta pa ; status register
sta pk
- lda pb
cmp pb
bne -
cmp #$ff
lda #$7f ;restore to default Kernal row selected (to the one
sta pa ; containing the STOP key)
lda #$ff
sta pk
rts
;global variables
scanTable .buf scanrows ;values of the eleven keyboard scan rows
newKeys .buf rollover ;codes of up to three keys held simultaneously
ignoreKeys .buf 1 ;flag: if an old key has been released and no
; new key has been pressed, stop all key
; repeating
prevKeys .buf rollover+2 ;keys held on previous scan
-----=-----
And that's all there is to it. :-)
5. THE C-64 KEYSCANNER
The boot program for the C-64 keyscanner is as follows:
10 d=peek(186)
20 if a=1 then 60
30 a=1
40 load"keyscan64",d,1
50 goto 10
60 sys 49152+5*256 : rem $c500
It is very much like boot programs for other machine language programs that
don't load at the start of BASIC. It will load the binary from the last
device accessed, and activate it.
A listing of the C-64 keyscanning code is not presented here because it is so
similar to the C-128 listing. The only things that are different are the
Kernal patches and the keyboard scanning (because the three extra rows don't
have to be scanned). The IRQ had to be substantially copied from the ROM,
again, to get at the call to the key scanning. Also, rather than taking
over the BASIC reset vector (since there isn't one), the NMI vector is
taken over to insure the survival of the key scanner after a RUN/STOP+RESTORE.
A bit of its preamble also had to be copied out of ROM to get at the good
stuff. If you want a copy of the C-64 listing, you can e-mail me.
6. UUENCODED FILES
Here are the binary executables in uuencoded form. The CRC32s of the four
files are as follows:
crc32 = 3398956287 for "keyscan128"
crc32 = 2301926894 for "keyscan64.boot"
crc32 = 1767081474 for "keyscan64"
crc32 = 1604419896 for "keyshow"
================================================================================