====== Reading the Keyboard ======
Information from various sources. Collected and partly written by FTC.
Reading the keyboard on the Commodore 64 (and C=128) can be done in two main ways. The first way is to use KERNAL routines. The benefit of this is that these routines will do a lot of work for you, and it will handle things like English keyboard layout versus Swedish keyboard layout. Different keyboard layout differs both with respect to what characters that are assigned to what keys, and with respect to the actual characters that are available on the keyboard. For example, Swedish C64 keyboards have the characters Å, Ä and Ö. On the other hand, using KERNAL might not be the way to go in case the default handling of the keyboard does not suit the purposes of your program.
The second way to read the keyboard is by accessing hardware registers related to the keyboard directly. This is mainly done by reading $DC01 and $DC02 (i.e. CIA1). The benefit of using this approach is especially salient when you have special needs not covered by the KERNAL routines, or when you are rather interested in the physical location of the keys than what character that is printed on them on the keyboard. An example: The JCH music editor is a bit weird to use when you use a Swedish C64 with Swedish keyboard layout because the functions of the editor are not actually associated with the physical locations of the keys on the keyboards, but with certain characters like ":". This means that the actual key to press is located at different places depending on what machine you use, and in this case, the key you need to press on a Swedish keyboard is less conveniently placed (in some cases the differences may even require the user to press SHIFT, or similar, to get the right character). Imagine that you wrote a game where you control the movement of the character with the keyboard and you use keys that you expect to be next to each other on the keyboard. You would not like this to be changed in some weird way in case someone happens not to use an English C64...
Below are some code examples, as well as links to code available in other articles here on Codebase. Also check out some of the books in the [[books:start|books]] section for more info on reading the keyboard.
===== Reading keyboard through KERNAL routines =====
Here are links to some material on Codebase that shows examples of how to use the KERNAL routines for reading keyboard input:
* [[base:robust_string_input|Robust String Input]] - by Schema
* [[base:ip_address_input|IP Address Input]] - by Schema
===== Reading keyboard directly through hardware =====
==== Simple case: One key at a time ====
Here is a simple example of using the hardware directly to read the keyboard. Written by Groepaz in ca65 assembler format. Simple keychecking (one key at a time, no extras):
minikey:
lda #$0
sta $dc03 ; port b ddr (input)
lda #$ff
sta $dc02 ; port a ddr (output)
lda #$00
sta $dc00 ; port a
lda $dc01 ; port b
cmp #$ff
beq nokey
; got column
tay
lda #$7f
sta nokey2+1
ldx #8
nokey2:
lda #0
sta $dc00 ; port a
sec
ror nokey2+1
dex
bmi nokey
lda $dc01 ; port b
cmp #$ff
beq nokey2
; got row in X
txa
ora columntab,y
sec
rts
nokey:
clc
rts
columntab:
.repeat 256,count
.if count = ($ff-$80)
.byte $70
.elseif count = ($ff-$40)
.byte $60
.elseif count = ($ff-$20)
.byte $50
.elseif count = ($ff-$10)
.byte $40
.elseif count = ($ff-$08)
.byte $30
.elseif count = ($ff-$04)
.byte $20
.elseif count = ($ff-$02)
.byte $10
.elseif count = ($ff-$01)
.byte $00
.else
.byte $ff
.endif
.endrepeat
==== Shift key + one other key ====
This code was written by Oswald.
lastkey = $10
actkey = $11
mask = $12
matrixlo = $13
matrixhi = $14
table = $0f00
*= $1000
lda #$37
sta $01
jsr $e544
sei
lda #$35
sta $01
ldx #$00
lda #$00
- sta table,x
dex
bne -
lda #$ff
sta lastkey
lda #$08 ;helper table to index into keyboard matrix
sta table+%01111111
lda #$07
sta table+%10111111
lda #$06
sta table+%11011111
lda #$05
sta table+%11101111
lda #$04
sta table+%11110111
lda #$03
sta table+%11111011
lda #$02
sta table+%11111101
lda #$01
sta table+%11111110
lda #$08 ;left shift and another key
sta table+%01111111
lda #$07
sta table+%00111111
lda #$06
sta table+%01011111
lda #$05
sta table+%01101111
lda #$04
sta table+%01110111
lda #$03
sta table+%01111011
lda #$02
sta table+%01111101
lda #$01
sta table+%01111110
lda #$08 ;right shift and another key
sta table+%01101111
lda #$07
sta table+%10101111
lda #$06
sta table+%11001111
lda #$05
sta table+%11101111
lda #$04
sta table+%11100111
lda #$03
sta table+%11101011
lda #$02
sta table+%11101101
lda #$01
sta table+%11101110
;endless dummy
uu jsr keyscan
lda actkey
cmp #$ff ;$ff= no key pressed
beq +
cmp #$40 ;convert to screen codes
bmi ok
sec
sbc #$40
ok
sta $0400
+ jmp uu
keyscan
lda #%11111110
sta mask
lda #%11111101
sta $dc00
lda $dc01
and #%10000000
beq shifted ;left shift pressed
lda #%10111111
sta $dc00
lda $dc01
and #%00010000
beq shifted ;right shift pressed
lda #keytabunshifted
sta matrixhi
jmp scan
shifted
lda #keytabshifted
sta matrixhi
scan ldx #$07
rowloop
lda mask
sta $dc00
ldy $dc01
lda table,y
beq next
tay
lda (matrixlo),y
cmp #$01
beq next ;skip left shift
cmp #$02
beq next ;skip right shift
cmp lastkey
beq debounce
sta lastkey
sta actkey
rts
next
sec
rol mask
lda matrixlo
clc
adc #$09
sta matrixlo
bcc *+4
inc matrixhi
dex
bpl rowloop
rts
debounce lda #$ff
sta actkey
rts
;unshifted
keytabunshifted
.byte $ff,$14,$0D,$1D,$88,$85,$86,$87,$11 ;0
.byte $ff,$33,$57,$41,$34,$5A,$53,$45,$01 ;1
.byte $ff,$35,$52,$44,$36,$43,$46,$54,$58 ;2
.byte $ff,$37,$59,$47,$38,$42,$48,$55,$56 ;3
.byte $ff,$39,$49,$4A,$30,$4D,$4B,$4F,$4E ;4
.byte $ff,$2B,$50,$4C,$2D,$2E,$3A,$40,$2C ;5
.byte $ff,$5C,$2A,$3B,$13,$01,$3D,$5E,$2F ;6
.byte $ff,$31,$5F,$04,$32,$20,$02,$51,$03 ;7
.byte $ff
keytabshifted
.byte $ff,$94,$8D,$9D,$8C,$89,$8A,$8B,$91
.byte $ff,$23,$D7,$C1,$24,$DA,$D3,$C5,$01
.byte $ff,$25,$D2,$C4,$26,$C3,$C6,$D4,$D8
.byte $ff,$27,$D9,$C7,$28,$C2,$C8,$D5,$D6
.byte $ff,$29,$C9,$CA,$30,$CD,$CB,$CF,$CE
.byte $ff,$DB,$D0,$CC,$DD,$3E,$5B,$BA,$3C
.byte $ff,$A9,$C0,$5D,$93,$01,$3D,$DE,$3F
.byte $ff,$21,$5F,$04,$22,$A0,$02,$D1,$83
.byte $ff
;one extra $ff column is added, because the zero value is used to detect unpressed kays
==== Handling three keys pressed at once ====
For a more complex routine, see "[[magazines:chacking6#three-key_rollover_for_the_c-128_and_c-64|THREE-KEY ROLLOVER for the C=128 and C=64]]” written by Craig Bruce and published in C=Hacking #6. It allows up to three keys pressed at once and also includes info on differences between C128 and C64 with respect to keyboard reading.
==== $DC00/$DC01 reference for English keyboards ====
Here is a reference table typed in by TWW that shows the characters assigned to the various keys on an English keyboard (but keep in mind that this table would actually look slightly different for a Swedish or German keyboard for example).
+----+----------------------+-------------------------------------------------------------------------------------------------------+
| | | Peek from $dc01 (code in paranthesis): |
|row:| $dc00: +------------+------------+------------+------------+------------+------------+------------+------------+
| | | BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0 |
+----+----------------------+------------+------------+------------+------------+------------+------------+------------+------------+
|1. | #%11111110 (254/$fe) | DOWN ($ )| F5 ($ )| F3 ($ )| F1 ($ )| F7 ($ )| RIGHT ($ )| RETURN($ )|DELETE ($ )|
|2. | #%11111101 (253/$fd) |LEFT-SH($ )| e ($05)| s ($13)| z ($1a)| 4 ($34)| a ($01)| w ($17)| 3 ($33)|
|3. | #%11111011 (251/$fb) | x ($18)| t ($14)| f ($06)| c ($03)| 6 ($36)| d ($04)| r ($12)| 5 ($35)|
|4. | #%11110111 (247/$f7) | v ($16)| u ($15)| h ($08)| b ($02)| 8 ($38)| g ($07)| y ($19)| 7 ($37)|
|5. | #%11101111 (239/$ef) | n ($0e)| o ($0f)| k ($0b)| m ($0d)| 0 ($30)| j ($0a)| i ($09)| 9 ($39)|
|6. | #%11011111 (223/$df) | , ($2c)| @ ($00)| : ($3a)| . ($2e)| - ($2d)| l ($0c)| p ($10)| + ($2b)|
|7. | #%10111111 (191/$bf) | / ($2f)| ^ ($1e)| = ($3d)|RGHT-SH($ )| HOME ($ )| ; ($3b)| * ($2a)| £ ($1c)|
|8. | #%01111111 (127/$7f) | STOP ($ )| q ($11)|COMMODR($ )| SPACE ($20)| 2 ($32)|CONTROL($ )| <- ($1f)| 1 ($31)|
+----+----------------------+------------+------------+------------+------------+------------+------------+------------+------------+