====== 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)| +----+----------------------+------------+------------+------------+------------+------------+------------+------------+------------+