User Tools

Site Tools


base:reading_the_keyboard

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 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:

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 matrixlo
	lda #>keytabunshifted
	sta matrixhi
	jmp scan

shifted
	lda #<keytabshifted
	sta matrixlo
	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 “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)|
+----+----------------------+------------+------------+------------+------------+------------+------------+------------+------------+
base/reading_the_keyboard.txt · Last modified: 2015-04-17 04:33 (external edit)